diff --git a/.eslintignore b/.eslintignore index 64c29f3..a515666 100755 --- a/.eslintignore +++ b/.eslintignore @@ -3,3 +3,4 @@ node_modules commitizen.config.js commitlint.config.js coverage +docs diff --git a/.eslintrc.js b/.eslintrc.js index 1432ca6..050991d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,8 +7,14 @@ module.exports = { parserOptions: { ecmaVersion: 2017, }, - plugins: ['prettier', 'jsdoc'], - extends: ['eslint:recommended', 'airbnb-base', 'plugin:prettier/recommended'], + plugins: ['prettier', 'jsdoc', 'promise', 'sonarjs'], + extends: [ + 'plugin:promise/recommended', + 'plugin:sonarjs/recommended', + 'eslint:recommended', + 'airbnb-base', + 'plugin:prettier/recommended', + ], rules: { // Only allow debugger in development 'no-debugger': process.env.PRE_COMMIT ? 'error' : 'off', @@ -59,5 +65,7 @@ module.exports = { 'jsdoc/require-returns-description': 'off', 'jsdoc/require-returns-type': 'warn', 'jsdoc/valid-types': 'warn', + 'promise/prefer-await-to-then': 'warn', + 'promise/prefer-await-to-callbacks': 'warn', }, }; diff --git a/.prettierignore b/.prettierignore index 3e372f0..ca98ee0 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ /node_modules/** **/output.css +docs diff --git a/README.md b/README.md index c428cb9..ed28e3a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Projects with a large number of sprites can take a long time to compile. The hel ## Relative/absolute paths -The plugin supports both relative andabsolute paths on input file, but can currently only [generate relative paths on output file](https://github.com/glebmachine/postcss-easysprites/issues/4). +The plugin supports both relative and absolute paths on input file, but can currently only [generate relative paths on output file](https://github.com/glebmachine/postcss-easysprites/issues/4). ## Plugin options diff --git a/commitizen.config.js b/commitizen.config.js index 01422e1..c6aa832 100644 --- a/commitizen.config.js +++ b/commitizen.config.js @@ -46,7 +46,6 @@ const scopes = [ 'gulp', 'jest', 'jsdoc', - 'lodash', 'mocha', 'nodejs', 'npm', diff --git a/index.js b/index.js index c815578..ba7d717 100755 --- a/index.js +++ b/index.js @@ -13,31 +13,20 @@ const { mapSpritesProperties, saveSprites } = require('./lib/sprites'); * @param {processOptions} [options] Options passed to the plugin. */ module.exports = postcss.plugin('postcss-easysprites', (options) => { - return (css) => { + return async (css) => { // Setup options. pluginOptions.init(options, css.source.input.file); - return Promise.all([collectImages(css)]) - .then(([images]) => { - return addSpriteGroups(images); - }) - .then(([images]) => { - return setTokens(images, css); - }) - .then(([images]) => { - return runSpritesmith(images); - }) - .then(([images, sprites]) => { - return saveSprites(images, sprites); - }) - .then(([images, sprites]) => { - return mapSpritesProperties(images, sprites); - }) - .then(([images, sprites]) => { - return updateReferences(images, sprites, css); - }) - .catch((err) => { - throw new Error(err); - }); + try { + const images = await collectImages(css); + await addSpriteGroups(images); + await setTokens(images, css); + const sprites = await runSpritesmith(images); + await saveSprites(images, sprites); + await mapSpritesProperties(images, sprites); + await updateReferences(images, sprites, css); + } catch (error) { + throw new Error(error); + } }; }); diff --git a/jsdoc.conf.json b/jsdoc.conf.json new file mode 100644 index 0000000..520d157 --- /dev/null +++ b/jsdoc.conf.json @@ -0,0 +1,25 @@ +{ + "plugins": [], + "recurseDepth": 10, + "source": { + "include": ["lib"], + "includePattern": ".+\\.js(doc|x)?$", + "excludePattern": "(^|\\/|\\\\)_" + }, + "sourceType": "module", + "tags": { + "allowUnknownTags": true, + "dictionaries": ["jsdoc", "closure"] + }, + "templates": { + "cleverLinks": false, + "monospaceLinks": false + }, + "opts": { + "template": "templates/default", + "encoding": "utf8", + "destination": "./docs/", + "recurse": true, + "readme": "README.md" + } +} diff --git a/lib/cache.js b/lib/cache.js index bac379c..47b54fa 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -1,5 +1,9 @@ const fs = require('fs'); const md5 = require('md5'); +const { promisify } = require('util'); + +const readFileAsync = promisify(fs.readFile); + /** * Custom module to cache sprite images so unchanged sprites don't need to be * processed by Spritesmith. @@ -8,12 +12,24 @@ const cache = { cache: {}, cacheIndex: {}, - createCacheHash(imagePaths) { - const cacheHashes = imagePaths.map((imagePath) => { - return `${imagePath}=${md5(fs.readFileSync(imagePath).toString())}`; + async createCacheHash(imagePaths) { + const allPromisedCacheHashes = imagePaths.map(async (imagePath) => { + try { + const image = await readFileAsync(imagePath); + return `${imagePath}=${md5(image.toString())}`; + } catch (error) { + return undefined; + } }); - return md5(cacheHashes.sort().join('&')); + const cacheHashes = await Promise.all(allPromisedCacheHashes); + + const hashString = cacheHashes + .filter((cacheHash) => cacheHash) + .sort() + .join('&'); + + return hashString ? md5(hashString) : undefined; }, getCache() { return this.cache; diff --git a/lib/collect-images.js b/lib/collect-images.js index f78d7bb..2f046bb 100644 --- a/lib/collect-images.js +++ b/lib/collect-images.js @@ -1,12 +1,12 @@ const fs = require('fs'); const { promisify } = require('util'); const ansi = require('ansi-colors'); -const lodash = require('lodash'); const url = require('url'); + +const fsAccessAsync = promisify(fs.access); const { log } = require('./log'); const { isRetinaImage, getRetinaRatio } = require('./retina-images'); const { pluginOptions } = require('./plugin-options'); - const { isLocalUrl, hasImageInRule, @@ -66,46 +66,42 @@ function buildImageData(cssRule) { * @returns {boolean} */ async function fileExistsAsync(path) { - const fsAccessAsync = promisify(fs.access); - - const fileExists = await fsAccessAsync(path) - .then(() => true) - .catch(() => false); - - return fileExists; + try { + await fsAccessAsync(path); + return true; + } catch (error) { + return false; + } } /** * Checks if a image actually exists. * * @param {object} image - Object of image properties. - * @param {Array} ruleNodes - The css rule nodes. - * @param {Array} images - The array of images that exist. + * @param {Array} rules - The css rule nodes. * @returns {Promise} */ -function imageExists(image, ruleNodes, images) { - return fileExistsAsync(image.path) - .then((result) => { - if (result) { - images.push(image); - } else { - log( - 'Easysprites:', - ansi.red(image.path), - 'file unreachable or does not exists' - ); - - // If the image file doesn't exist, clean up the background image URL's - // by removing hash suffix. - ruleNodes.forEach((node) => { - const nodeRule = node; - nodeRule.value = node.value.replace(`#${image.hash}`, ''); - }); - } - }) - .catch((error) => { - throw new Error(error); - }); +async function imageExists(image, rules) { + const exists = await fileExistsAsync(image.path); + + if (exists) { + return image; + } + + log( + 'Easysprites:', + ansi.red(image.path), + 'file unreachable or does not exists' + ); + + // If the image file doesn't exist, clean up the background image URL's + // by removing hash suffix. + rules.forEach((node) => { + const nodeRule = node; + nodeRule.value = node.value.replace(`#${image.hash}`, ''); + }); + + return undefined; } /** @@ -114,31 +110,33 @@ function imageExists(image, ruleNodes, images) { * @param {object} css - Object with CSS results. * @returns {Array} */ -function collectImages(css) { +async function collectImages(css) { const images = []; - let allImagesChecked; - return new Promise((resolve) => { - // Loop through all CSS rules. - css.walkRules((rule) => { - // Get the string representation of the PostCSS rule object. - const cssRule = rule.toString(); + // Loop through all CSS rules. + css.walkRules((rule) => { + // Get the string representation of the PostCSS rule object. + const cssRule = rule.toString(); - // Check if there is a `background(-image)` rule with a url() defined. - if (!hasImageInRule(cssRule)) return; + // Check if there is a `background(-image)` rule with a url() defined. + if (!hasImageInRule(cssRule)) return; - const image = buildImageData(cssRule); - if (!image) return; + const image = buildImageData(cssRule); + if (!image) return; - allImagesChecked = imageExists(image, rule.nodes, images); - }); - - return allImagesChecked - ? allImagesChecked.then(() => { - resolve(lodash.uniqWith(images, lodash.isEqual)); - }) - : resolve(images); + images.push(imageExists(image, rule.nodes)); }); + + const allFoundImages = await Promise.all(images).then((array) => + array.filter((image) => !!image) + ); + + // Return an array with all duplicates removed. + return [ + ...new Map( + allFoundImages.map((obj) => [JSON.stringify(obj), obj]) + ).values(), + ]; } exports.collectImages = collectImages; diff --git a/lib/retina-images.js b/lib/retina-images.js index 7bad748..a910991 100644 --- a/lib/retina-images.js +++ b/lib/retina-images.js @@ -23,9 +23,7 @@ function getRetinaRatio(imageUrl) { const matches = retinaPattern.exec(imageUrl.split('#')[0]); // Convert the string number to an actual integer. - const ratio = parseInt(matches[1], 10); - - return ratio; + return parseInt(matches[1], 10); } /** diff --git a/lib/run-spritesmith.js b/lib/run-spritesmith.js index 0d1c5bd..79ad6d7 100644 --- a/lib/run-spritesmith.js +++ b/lib/run-spritesmith.js @@ -1,5 +1,4 @@ const { promisify } = require('util'); -const lodash = require('lodash'); const spritesmith = promisify(require('spritesmith').run); const { areAllRetina, getRetinaPadding } = require('./retina-images'); @@ -34,34 +33,57 @@ function buildSpritesmithConfig(spriteImages, spriteGroup) { return config; } +/** + * Group image objects by their concatenated sprite group names. + * + * @param {Array} images - Array of image objects. + * @returns {object} + */ +function groupImagesBySpriteName(images) { + const imagesByGroup = {}; + + images.reduce((acc, image) => { + acc.push(image); + + const key = `${image.groups.join('')}`; + + imagesByGroup[key] = acc.filter( + (item) => key === `${item.groups.join('')}` + ); + + return acc; + }, []); + + return imagesByGroup; +} + /** * Run SpriteSmith on the array of images. * * @param {Array} images - Array of image objects. * @returns {Array} */ -function runSpritesmith(images) { - return new Promise((resolve, reject) => { - const allSprites = lodash - .chain(images) - // Group image objects by their concatenated sprite group names. - .groupBy((image) => image.groups.join('')) - .map(async (spriteImages, spriteGroup) => { - const config = buildSpritesmithConfig(spriteImages, spriteGroup); - - // Calculate the sprite cache hash to use for checking if the sprite - // image has already been generated. - const cacheHash = cache.createCacheHash(config.src); - - // If a sprite is found in the cache, return it instead of having - // spritesmith regenerate a new one. - if (cache.isItemCached(cacheHash)) { - cache.markAsCached(cacheHash); - return cache.getCacheItem(cacheHash); - } +async function runSpritesmith(images) { + const groupedImages = groupImagesBySpriteName(images); + + const allNewSprites = Object.entries(groupedImages).map( + async ([spriteGroup, spriteImages]) => { + const config = buildSpritesmithConfig(spriteImages, spriteGroup); + // Calculate the sprite cache hash to use for checking if the sprite + // image has already been generated. + const cacheHash = await cache.createCacheHash(config.src); + + // If a sprite is found in the cache, return it instead of having + // spritesmith regenerate a new one. + if (cache.isItemCached(cacheHash)) { + cache.markAsCached(cacheHash); + return cache.getCacheItem(cacheHash); + } + + try { // Generate the spritesheet with spritesmith. - const spritesheet = await spritesmith(config).then((result) => result); + const spritesheet = await spritesmith(config); // Append info about sprite group. spritesheet.groups = spriteGroup; @@ -79,17 +101,13 @@ function runSpritesmith(images) { cache.addCacheItem(cacheHash, spritesheet); return spritesheet; - }) - .value(); - - Promise.all(allSprites) - .then((results) => { - resolve([images, results]); - }) - .catch((err) => reject(err)); - }).catch((error) => { - throw new Error(`Spritesmith failed to generate sprites. ${error}`); - }); + } catch (error) { + throw new Error(`Spritesmith failed to generate sprites. ${error}`); + } + } + ); + + return Promise.all(allNewSprites); } exports.runSpritesmith = runSpritesmith; diff --git a/lib/sprite-groups.js b/lib/sprite-groups.js index cbab603..307ba70 100644 --- a/lib/sprite-groups.js +++ b/lib/sprite-groups.js @@ -7,19 +7,13 @@ function addSpriteGroups(images) { const groupedImages = images.map((image) => { const { groups, ratio } = image; - const spriteGroups = []; - - // Add any existing groups. - spriteGroups.push(...groups); + const imageWithGroup = image; // Add any retina groups. - if (ratio > 1) { - spriteGroups.push(`@${ratio}x`); - } + const retinaGroup = ratio > 1 ? [`@${ratio}x`] : []; - const imageWithGroup = image; // Add sprite group to image object. - imageWithGroup.groups = spriteGroups; + imageWithGroup.groups = [...groups, ...retinaGroup]; return imageWithGroup; }); diff --git a/lib/sprites.js b/lib/sprites.js index 77523b0..ebd4b18 100644 --- a/lib/sprites.js +++ b/lib/sprites.js @@ -1,13 +1,12 @@ const { promisify } = require('util'); -const lodash = require('lodash'); const path = require('path'); const { writeFile } = require('fs'); const mkdirp = promisify(require('mkdirp')); const ansi = require('ansi-colors'); -const { log } = require('./log'); -const { pluginOptions } = require('./plugin-options'); const writeFileAsync = promisify(writeFile); +const { log } = require('./log'); +const { pluginOptions } = require('./plugin-options'); /** * Map properties for every image. @@ -18,7 +17,9 @@ const writeFileAsync = promisify(writeFile); */ function mapSpritesProperties(images, sprites) { const spriteProperties = sprites.map((sprite) => { - return lodash.map(sprite.coordinates, (coordinates, imagePath) => { + const imagePaths = Object.keys(sprite.coordinates); + + return imagePaths.map((imagePath) => { // Retrieve the existing image object with the same image path. const matchingImage = images.find( (element) => element.path === imagePath @@ -27,7 +28,7 @@ function mapSpritesProperties(images, sprites) { // Add the sprite information to the image object and return a copy // of the object. return Object.assign(matchingImage, { - coordinates, + coordinates: sprite.coordinates[imagePath], spritePath: sprite.path, properties: sprite.properties, }); @@ -43,7 +44,7 @@ function mapSpritesProperties(images, sprites) { * @param {object} spriteElement - The sprite element that will be saved. * @returns {Promise} */ -function saveSpriteFile(spriteElement) { +async function saveSpriteFile(spriteElement) { const opts = pluginOptions.getOptions(); const sprite = spriteElement; @@ -57,12 +58,11 @@ function saveSpriteFile(spriteElement) { } // Save new version of the sprite image file. - return writeFileAsync(sprite.path, Buffer.from(sprite.image, 'binary')).then( - () => { - log('Easysprites:', ansi.yellow(sprite.path), 'generated.'); - return sprite; - } - ); + await writeFileAsync(sprite.path, Buffer.from(sprite.image, 'binary')); + + log('Easysprites:', ansi.yellow(sprite.path), 'generated.'); + + return sprite; } /** @@ -75,25 +75,23 @@ function saveSpriteFile(spriteElement) { async function saveSprites(images, sprites) { const opts = pluginOptions.getOptions(); - return mkdirp(opts.spritePath) - .then(async () => { - const finished = await Promise.all( - sprites.map((sprite) => saveSpriteFile(sprite)) - ) - .then((allSprites) => { - return allSprites; - }) - .catch((error) => { - throw new Error(`Sprite file failed to save. ${error}`); - }); - - return [images, finished]; - }) - .catch((error) => { - throw new Error( - `The directory ${opts.spritePath} could not be created. ${error}` - ); - }); + try { + await mkdirp(opts.spritePath); + } catch (error) { + throw new Error( + `The directory ${opts.spritePath} could not be created. ${error}` + ); + } + + try { + const allSavedSprites = await Promise.all( + sprites.map((sprite) => saveSpriteFile(sprite)) + ); + + return [images, allSavedSprites]; + } catch (error) { + throw new Error(`Sprite file failed to save. ${error}`); + } } exports.mapSpritesProperties = mapSpritesProperties; diff --git a/lib/tokens.js b/lib/tokens.js index e437536..130dec2 100644 --- a/lib/tokens.js +++ b/lib/tokens.js @@ -96,7 +96,7 @@ function setTokens(images, css) { } // Set the comment information as a token on the image. - setCommentToken(image, decl); + setCommentToken(image); // Replace the declaration with a comment token // which will be used later for reference. diff --git a/package-lock.json b/package-lock.json index b9fe896..444885d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "postcss-easysprites", - "version": "1.0.0-alpha.2", + "version": "1.0.0-beta.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -566,9 +566,9 @@ } }, "@sinonjs/samsam": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.1.tgz", - "integrity": "sha512-wRSfmyd81swH0hA1bxJZJ57xr22kC07a1N4zuIL47yTS04bDk6AoCkczcqHEjcRPmJ+FruGJ9WBQiJwMtIElFw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.2.tgz", + "integrity": "sha512-ILO/rR8LfAb60Y1Yfp9vxfYAASK43NFC2mLzpvLUbCQY/Qu8YwReboseu8aheCEkyElZF2L2T9mHcR2bgdvZyA==", "dev": true, "requires": { "@sinonjs/commons": "^1.0.2", @@ -1202,6 +1202,12 @@ "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, + "bluebird": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1354,6 +1360,15 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "catharsis": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz", + "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, "center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", @@ -1808,22 +1823,22 @@ } }, "conventional-changelog": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.8.tgz", - "integrity": "sha512-fb3/DOLLrQdNqN0yYn/lT6HcNsAa9A+VTDBqlZBMQcEPPIeJIMI+DBs3yu+eiYOLi22w9oShq3nn/zN6qm1Hmw==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.10.tgz", + "integrity": "sha512-6RDj31hL39HUkpqvPjRlOxAwJRwur8O2qu9m6R0FBNDGwCJyy4SYH9NfyshozxYSeklrauKRf3oSbyoEZVzu9Q==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.3", "conventional-changelog-atom": "^2.0.1", "conventional-changelog-codemirror": "^2.0.1", - "conventional-changelog-conventionalcommits": "^3.0.2", - "conventional-changelog-core": "^3.2.2", + "conventional-changelog-conventionalcommits": "^4.1.0", + "conventional-changelog-core": "^4.0.0", "conventional-changelog-ember": "^2.0.2", "conventional-changelog-eslint": "^3.0.2", "conventional-changelog-express": "^2.0.1", "conventional-changelog-jquery": "^3.0.4", "conventional-changelog-jshint": "^2.0.1", - "conventional-changelog-preset-loader": "^2.1.1" + "conventional-changelog-preset-loader": "^2.2.0" }, "dependencies": { "conventional-changelog-angular": { @@ -1858,14 +1873,14 @@ } }, "conventional-changelog-cli": { - "version": "2.0.21", - "resolved": "https://registry.npmjs.org/conventional-changelog-cli/-/conventional-changelog-cli-2.0.21.tgz", - "integrity": "sha512-gMT1XvSVmo9Np1WUXz8Mvt3K+OtzR+Xu13z0jq/3qsXBbLuYc2/oaUXVr68r3fYOL8E9dN2uvX7Hc7RkeWvRVA==", + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/conventional-changelog-cli/-/conventional-changelog-cli-2.0.23.tgz", + "integrity": "sha512-a/jDZHEUpSHQMAqeDrmrFhz9CKHBKhBGpJyc38BCfNjFA1RKchpq/Qqbo1BZwRLWrW/PX7IGsUicTyhniqUH9g==", "dev": true, "requires": { "add-stream": "^1.0.0", - "conventional-changelog": "^3.1.8", - "lodash": "^4.2.1", + "conventional-changelog": "^3.1.10", + "lodash": "^4.14.14", "meow": "^4.0.0", "tempfile": "^1.1.1" }, @@ -1962,9 +1977,9 @@ } }, "conventional-changelog-conventionalcommits": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-3.0.2.tgz", - "integrity": "sha512-w1+fQSDnm/7+sPKIYC5nfRVYDszt+6HdWizrigSqWFVIiiBVzkHGeqDLMSHc+Qq9qssHVAxAak5206epZyK87A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.1.0.tgz", + "integrity": "sha512-J3xolGrH8PTxpCqueHOuZtv3Cp73SQOWiBQzlsaugZAZ+hZgcJBonmC+1bQbfGs2neC2S18p2L1Gx+nTEglJTQ==", "dev": true, "requires": { "compare-func": "^1.3.1", @@ -1972,18 +1987,18 @@ } }, "conventional-changelog-core": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-3.2.2.tgz", - "integrity": "sha512-cssjAKajxaOX5LNAJLB+UOcoWjAIBvXtDMedv/58G+YEmAXMNfC16mmPl0JDOuVJVfIqM0nqQiZ8UCm8IXbE0g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.0.0.tgz", + "integrity": "sha512-+bZMeBUdjKxfyX2w6EST9U7zb85wxrGS3IV4H7SqPya44osNQbm3P+vyqfLs6s57FkoEamC93ioDEiguVLWmSQ==", "dev": true, "requires": { - "conventional-changelog-writer": "^4.0.5", - "conventional-commits-parser": "^3.0.2", + "conventional-changelog-writer": "^4.0.7", + "conventional-commits-parser": "^3.0.3", "dateformat": "^3.0.0", "get-pkg-repo": "^1.0.0", "git-raw-commits": "2.0.0", "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^2.0.2", + "git-semver-tags": "^3.0.0", "lodash": "^4.2.1", "normalize-package-data": "^2.3.5", "q": "^1.5.1", @@ -2244,21 +2259,21 @@ } }, "conventional-changelog-preset-loader": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.1.1.tgz", - "integrity": "sha512-K4avzGMLm5Xw0Ek/6eE3vdOXkqnpf9ydb68XYmCc16cJ99XMMbc2oaNMuPwAsxVK6CC1yA4/I90EhmWNj0Q6HA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.2.0.tgz", + "integrity": "sha512-zXB+5vF7D5Y3Cb/rJfSyCCvFphCVmF8mFqOdncX3BmjZwAtGAPfYrBcT225udilCKvBbHgyzgxqz2GWDB5xShQ==", "dev": true }, "conventional-changelog-writer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.6.tgz", - "integrity": "sha512-ou/sbrplJMM6KQpR5rKFYNVQYesFjN7WpNGdudQSWNi6X+RgyFUcSv871YBYkrUYV9EX8ijMohYVzn9RUb+4ag==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.7.tgz", + "integrity": "sha512-p/wzs9eYaxhFbrmX/mCJNwJuvvHR+j4Fd0SQa2xyAhYed6KBiZ780LvoqUUvsayP4R1DtC27czalGUhKV2oabw==", "dev": true, "requires": { "compare-func": "^1.3.1", "conventional-commits-filter": "^2.0.2", "dateformat": "^3.0.0", - "handlebars": "^4.1.0", + "handlebars": "^4.1.2", "json-stringify-safe": "^5.0.1", "lodash": "^4.2.1", "meow": "^4.0.0", @@ -2353,9 +2368,9 @@ } }, "semver": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", - "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "string_decoder": { @@ -3021,6 +3036,12 @@ "once": "^1.4.0" } }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3433,6 +3454,18 @@ "prettier-linter-helpers": "^1.0.0" } }, + "eslint-plugin-promise": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", + "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", + "dev": true + }, + "eslint-plugin-sonarjs": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.4.0.tgz", + "integrity": "sha512-l8E4ueMKVtEcocINHSNVH/YBSmDDXZlPEbud7bagRGyoCeB0otoyltoro5kdnIvVzS5usUwvjzMocHnPax2FEw==", + "dev": true + }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", @@ -5101,13 +5134,13 @@ } }, "git-semver-tags": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-2.0.2.tgz", - "integrity": "sha512-34lMF7Yo1xEmsK2EkbArdoU79umpvm0MfzaDkSNYSJqtM5QLAVTPWgpiXSVI5o/O9EvZPSrP4Zvnec/CqhSd5w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-3.0.0.tgz", + "integrity": "sha512-T4C/gJ9k2Bnxz+PubtcyiMtUUKrC+Nh9Q4zaECcnmVMwJgPhrNyP/Rf+YpdRqsJbCV/+kYrCH24Xg+IeAmbOPg==", "dev": true, "requires": { "meow": "^4.0.0", - "semver": "^5.5.0" + "semver": "^6.0.0" }, "dependencies": { "find-up": { @@ -5185,9 +5218,9 @@ } }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "strip-bom": { @@ -5913,9 +5946,9 @@ } }, "husky": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.1.tgz", - "integrity": "sha512-PXBv+iGKw23GHUlgELRlVX9932feFL407/wHFwtsGeArp0dDM4u+/QusSQwPKxmNgjpSL+ustbOdQ2jetgAZbA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.3.tgz", + "integrity": "sha512-DBBMPSiBYEMx7EVUTRE/ymXJa/lOL+WplcsV/lZu+/HHGt0gzD+5BIz9EJnCrWyUa7hkMuBh7/9OZ04qDkM+Nw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -5925,7 +5958,7 @@ "is-ci": "^2.0.0", "opencollective-postinstall": "^2.0.2", "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.1.1", + "please-upgrade-node": "^3.2.0", "read-pkg": "^5.1.1", "run-node": "^1.0.0", "slash": "^3.0.0" @@ -6633,11 +6666,56 @@ } } }, + "js2xmlparser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.0.tgz", + "integrity": "sha512-WuNgdZOXVmBk5kUPMcTcVUpbGRzLfNkv7+7APq7WiDihpXVKrgxo6wwRpRl9OQeEBgKCVk9mR7RbzrnNWC8oBw==", + "dev": true, + "requires": { + "xmlcreate": "^2.0.0" + } + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, + "jsdoc": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.3.tgz", + "integrity": "sha512-Yf1ZKA3r9nvtMWHO1kEuMZTlHOF8uoQ0vyo5eH7SQy5YeIiHM+B0DgKnn+X6y6KDYZcF7G2SPkKF+JORCXWE/A==", + "dev": true, + "requires": { + "@babel/parser": "^7.4.4", + "bluebird": "^3.5.4", + "catharsis": "^0.8.11", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.0", + "klaw": "^3.0.0", + "markdown-it": "^8.4.2", + "markdown-it-anchor": "^5.0.2", + "marked": "^0.7.0", + "mkdirp": "^0.5.1", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.0.1", + "taffydb": "2.6.2", + "underscore": "~1.9.1" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + } + } + }, "jsdoctypeparser": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-4.0.0.tgz", @@ -6729,6 +6807,15 @@ "is-buffer": "^1.1.5" } }, + "klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, "last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", @@ -6843,6 +6930,15 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", "dev": true }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", @@ -6888,7 +6984,8 @@ "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true }, "lodash._reinterpolate": { "version": "3.0.0", @@ -6973,9 +7070,9 @@ } }, "lolex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.1.0.tgz", - "integrity": "sha512-BYxIEXiVq5lGIXeVHnsFzqa1TxN5acnKnPCdlZSpzm8viNEOhiigupA4vTQ9HEFQ6nLTQ9wQOgBknJgzUYQ9Aw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", "dev": true }, "longest": { @@ -7074,6 +7171,31 @@ "object-visit": "^1.0.0" } }, + "markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + }, + "markdown-it-anchor": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.2.4.tgz", + "integrity": "sha512-n8zCGjxA3T+Mx1pG8HEgbJbkB8JFUuRkeTZQuIM8iPY6oQ8sWOPRZJDFC9a/pNg2QkHEjjGkhBEl/RSyzaDZ3A==", + "dev": true + }, + "marked": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", + "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", + "dev": true + }, "matchdep": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", @@ -7119,6 +7241,12 @@ "is-buffer": "~1.1.1" } }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, "mem": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", @@ -7803,12 +7931,12 @@ "dev": true }, "nise": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.0.tgz", - "integrity": "sha512-Z3sfYEkLFzFmL8KY6xnSJLRxwQwYBjOXi/24lb62ZnZiGA0JUzGGTI6TBIgfCSMIDl9Jlu8SRmHNACLTemDHww==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.1.tgz", + "integrity": "sha512-edFWm0fsFG2n318rfEnKlTZTkjlbVOFF9XIA+fj+Ed+Qz1laYW2lobwavWoMzGrYDHH1EpiNJgDfvGnkZztR/g==", "dev": true, "requires": { - "@sinonjs/formatio": "^3.1.0", + "@sinonjs/formatio": "^3.2.1", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", "lolex": "^4.1.0", @@ -8722,9 +8850,9 @@ } }, "please-upgrade-node": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz", - "integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", "dev": true, "requires": { "semver-compare": "^1.0.0" @@ -9268,6 +9396,15 @@ } } }, + "requizzle": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", + "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, "resolve": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", @@ -9873,17 +10010,17 @@ "dev": true }, "sinon": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.3.2.tgz", - "integrity": "sha512-thErC1z64BeyGiPvF8aoSg0LEnptSaWE7YhdWWbWXgelOyThent7uKOnnEh9zBxDbKixtr5dEko+ws1sZMuFMA==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.4.1.tgz", + "integrity": "sha512-7s9buHGHN/jqoy/v4bJgmt0m1XEkCEd/tqdHXumpBp0JSujaT4Ng84JU5wDdK4E85ZMq78NuDe0I3NAqXY8TFg==", "dev": true, "requires": { "@sinonjs/commons": "^1.4.0", "@sinonjs/formatio": "^3.2.1", - "@sinonjs/samsam": "^3.3.1", + "@sinonjs/samsam": "^3.3.2", "diff": "^3.5.0", - "lolex": "^4.0.1", - "nise": "^1.4.10", + "lolex": "^4.2.0", + "nise": "^1.5.1", "supports-color": "^5.5.0" } }, @@ -10470,6 +10607,12 @@ } } }, + "taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", + "dev": true + }, "temp": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.0.tgz", @@ -10834,6 +10977,12 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", @@ -10856,6 +11005,12 @@ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, + "underscore": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==", + "dev": true + }, "undertaker": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", @@ -11315,6 +11470,12 @@ "signal-exit": "^3.0.2" } }, + "xmlcreate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.1.tgz", + "integrity": "sha512-MjGsXhKG8YjTKrDCXseFo3ClbMGvUD4en29H2Cev1dv4P/chlpw6KdYmlCWDkhosBVKRDjM836+3e3pm1cBNJA==", + "dev": true + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", diff --git a/package.json b/package.json index 37d1876..8a39698 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postcss-easysprites", - "version": "1.0.0-alpha.3", + "version": "1.0.0-beta.1", "description": "PostCSS plugin that generate sprites, like postcss-sprites, but proper way", "keywords": [ "postcss", @@ -33,7 +33,6 @@ "ansi-colors": "^4.1.1", "css-color-names": "^1.0.1", "fancy-log": "^1.3.3", - "lodash": "^4.17.15", "md5": "^2.2.1", "mkdirp": "^0.5.1", "postcss": "^7.0.17", @@ -45,7 +44,7 @@ "chai": "^4.0.0", "chai-as-promised": "^7.1.1", "commitizen": "^3.1.2", - "conventional-changelog-cli": "^2.0.21", + "conventional-changelog-cli": "^2.0.23", "cz-customizable": "^6.2.0", "del": "^5.0.0", "eslint": "^5.16.0", @@ -54,6 +53,8 @@ "eslint-plugin-import": "^2.18.2", "eslint-plugin-jsdoc": "^8.7.0", "eslint-plugin-prettier": "^3.1.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-sonarjs": "^0.4.0", "eslint-watch": "^5.1.2", "fixture-stdout": "^0.2.1", "gulp": "^4.0.2", @@ -61,7 +62,8 @@ "gulp-mocha": "^6.0.0", "gulp-postcss": "^8.0.0", "gulp-rename": "^1.4.0", - "husky": "^3.0.1", + "husky": "^3.0.3", + "jsdoc": "^3.6.3", "mocha": "^6.2.0", "mocha-performance": "^0.1.1", "nyc": "^14.1.1", @@ -70,7 +72,7 @@ "prettier": "^1.18.2", "rewire": "^4.0.1", "rimraf": "^2.6.3", - "sinon": "^7.3.2" + "sinon": "^7.4.1" }, "scripts": { "test": "gulp test", @@ -83,7 +85,8 @@ "mocha": "mocha", "perf": "node --prof ./node_modules/mocha/bin/_mocha", "performance": "node --allow-natives-syntax ./node_modules/mocha/bin/_mocha --reporter mocha-performance ./test/**/*.js", - "coverage": "nyc --reporter=text-summary --reporter=html --reporter=text --reporter=lcov mocha --recursive --timeout 5000" + "coverage": "nyc --reporter=text-summary --reporter=html --reporter=text --reporter=lcov mocha --recursive --timeout 5000", + "docs": "jsdoc -c jsdoc.conf.json" }, "config": { "commitizen": { diff --git a/test/basic.test.js b/test/basic.test.js index dbde665..52880ef 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -90,8 +90,8 @@ describe('Basic', function() { testOptions.padding = 100; assertEqual( - 'a { background-image: url("images/arrow-next.png#elements"); }', - 'a { background-image: url(sprites/elements.png); background-position: 0 0; }', + 'a { background-image: url("images/arrow-next.png#elements"); outline: none; }', + 'a { background-image: url(sprites/elements.png); background-position: 0 0; outline: none; }', testOptions, done ); diff --git a/test/caching.test.js b/test/caching.test.js index 8954a66..9bbd03a 100644 --- a/test/caching.test.js +++ b/test/caching.test.js @@ -35,55 +35,58 @@ function uncacheLog() { return logCapture.toString(); } -const assertNotCached = (input, output, opts, done) => { +const assertNotCached = async (input, output, opts, done) => { // Start stdout log capture. cacheLog(); - postcss([plugin(opts)]) - .process(input, { from: undefined }) - .then((result) => { - expect(result.css).to.eql(output); - // eslint-disable-next-line - expect(result.warnings()).to.be.empty; + try { + const result = await postcss([plugin(opts)]).process(input, { + from: undefined, + }); - // Stop stdout capture. - fixture.release(); + expect(result.css).to.eql(output); - if (uncacheLog().indexOf('generated') === -1) { - return done(new Error('Sprite already cached, code red!')); - } + // eslint-disable-next-line + expect(result.warnings()).to.be.empty; - return done(); - }) - .catch((error) => { - done(error); - }); + // Stop stdout capture. + fixture.release(); + + if (uncacheLog().indexOf('generated') === -1) { + return done(new Error('Sprite already cached, code red!')); + } + } catch (error) { + done(error); + } + + return done(); }; -const assertCached = (input, output, opts, done) => { +const assertCached = async (input, output, opts, done) => { // Start stdout log capture. cacheLog(); - postcss([plugin(opts)]) - .process(input, { from: undefined }) - .then((result) => { - expect(result.css).to.eql(output); + try { + const result = await postcss([plugin(opts)]).process(input, { + from: undefined, + }); - // eslint-disable-next-line - expect(result.warnings()).to.be.empty; + expect(result.css).to.eql(output); - // Stop stdout capture. - fixture.release(); + // eslint-disable-next-line + expect(result.warnings()).to.be.empty; - if (uncacheLog().indexOf('unchanged') === -1) { - return done(new Error('Cache is not working')); - } + // Stop stdout capture. + fixture.release(); - return done(); - }) - .catch((error) => { - done(error); - }); + if (uncacheLog().indexOf('unchanged') === -1) { + return done(new Error('Cache is not working')); + } + } catch (error) { + done(error); + } + + return done(); }; /* eslint-disable func-names */ diff --git a/test/collect-images.test.js b/test/collect-images.test.js index b824f95..59209be 100644 --- a/test/collect-images.test.js +++ b/test/collect-images.test.js @@ -1,6 +1,8 @@ const rewire = require('rewire'); const { expect } = require('chai'); +const util = require('util'); +const setTimeoutPromise = util.promisify(setTimeout); const collectImagesModule = rewire('../lib/collect-images'); /* eslint-disable func-names */ @@ -10,8 +12,12 @@ describe('Image Exists', function() { path: undefined, }; - const fileExistsAsync = () => { - return Promise.reject(new Error('fileExistsAsync failed')); + const fileExistsAsync = async () => { + await setTimeoutPromise(1000, 'fileExistsAsync failed').then( + (message) => { + throw new Error(message); + } + ); }; /* eslint-disable no-underscore-dangle */ diff --git a/test/demo/index.html b/test/demo/index.html index 49f6fd6..705659a 100644 --- a/test/demo/index.html +++ b/test/demo/index.html @@ -1,2 +1,5 @@ -
+
+ + +
diff --git a/test/fixtures/input.css b/test/fixtures/input.css index 4bbfc2e..4481d91 100644 --- a/test/fixtures/input.css +++ b/test/fixtures/input.css @@ -1,33 +1,67 @@ +.grid { + display: flex; + justify-content: space-around; +} + .arrow { width: 28px; height: 27px; margin: 10px auto; + display: block; } -.arrow { +.arrow--previous { + background-image: url('images/arrow-previous.png#elements'); +} + +.arrow--previous:hover { + background-image: url('images/arrow-previous--hover.png#elements'); +} + +@media only screen and (min-resolution: 1.5dppx) { + .arrow--previous { + background-image: url('images/arrow-previous@2x.png#elements'); + } + + .arrow--previous:hover { + background-image: url('images/arrow-previous--hover@2x.png#elements'); + } +} + +@media only screen and (min-resolution: 2.5dppx) { + .arrow--previous { + background-image: url('images/arrow-previous@3x.png#elements'); + } + + .arrow--previous:hover { + background-image: url('images/arrow-previous--hover@3x.png#elements'); + } +} + +.arrow--next { background-image: url('images/arrow-next.png#elements'); } -.arrow:hover { +.arrow--next:hover { background-image: url('images/arrow-next--hover.png#elements'); } @media only screen and (min-resolution: 1.5dppx) { - .arrow { + .arrow--next { background-image: url('images/arrow-next@2x.png#elements'); } - .arrow:hover { + .arrow--next:hover { background-image: url('images/arrow-next--hover@2x.png#elements'); } } @media only screen and (min-resolution: 2.5dppx) { - .arrow { + .arrow--next { background-image: url('images/arrow-next@3x.png#elements'); } - .arrow:hover { + .arrow--next:hover { background-image: url('images/arrow-next--hover@3x.png#elements'); } } diff --git a/test/fixtures/reference-sprites/elements.png b/test/fixtures/reference-sprites/elements.png index 21e6420..805e3b5 100644 Binary files a/test/fixtures/reference-sprites/elements.png and b/test/fixtures/reference-sprites/elements.png differ diff --git a/test/fixtures/reference-sprites/elements@2x.png b/test/fixtures/reference-sprites/elements@2x.png index 20c8e97..3523a85 100644 Binary files a/test/fixtures/reference-sprites/elements@2x.png and b/test/fixtures/reference-sprites/elements@2x.png differ diff --git a/test/fixtures/reference-sprites/elements@3x.png b/test/fixtures/reference-sprites/elements@3x.png index 9b37fd4..709a848 100644 Binary files a/test/fixtures/reference-sprites/elements@3x.png and b/test/fixtures/reference-sprites/elements@3x.png differ diff --git a/test/fixtures/reference-sprites/layouts/alt-diagonal/elements.png b/test/fixtures/reference-sprites/layouts/alt-diagonal/elements.png index 7126ea6..07b433b 100644 Binary files a/test/fixtures/reference-sprites/layouts/alt-diagonal/elements.png and b/test/fixtures/reference-sprites/layouts/alt-diagonal/elements.png differ diff --git a/test/fixtures/reference-sprites/layouts/alt-diagonal/elements@2x.png b/test/fixtures/reference-sprites/layouts/alt-diagonal/elements@2x.png index dd31c86..a62e053 100644 Binary files a/test/fixtures/reference-sprites/layouts/alt-diagonal/elements@2x.png and b/test/fixtures/reference-sprites/layouts/alt-diagonal/elements@2x.png differ diff --git a/test/fixtures/reference-sprites/layouts/alt-diagonal/elements@3x.png b/test/fixtures/reference-sprites/layouts/alt-diagonal/elements@3x.png index ee08b68..d4f9ae6 100644 Binary files a/test/fixtures/reference-sprites/layouts/alt-diagonal/elements@3x.png and b/test/fixtures/reference-sprites/layouts/alt-diagonal/elements@3x.png differ diff --git a/test/fixtures/reference-sprites/layouts/binary-tree/elements.png b/test/fixtures/reference-sprites/layouts/binary-tree/elements.png index 21e6420..805e3b5 100644 Binary files a/test/fixtures/reference-sprites/layouts/binary-tree/elements.png and b/test/fixtures/reference-sprites/layouts/binary-tree/elements.png differ diff --git a/test/fixtures/reference-sprites/layouts/binary-tree/elements@2x.png b/test/fixtures/reference-sprites/layouts/binary-tree/elements@2x.png index 20c8e97..3523a85 100644 Binary files a/test/fixtures/reference-sprites/layouts/binary-tree/elements@2x.png and b/test/fixtures/reference-sprites/layouts/binary-tree/elements@2x.png differ diff --git a/test/fixtures/reference-sprites/layouts/binary-tree/elements@3x.png b/test/fixtures/reference-sprites/layouts/binary-tree/elements@3x.png index 9b37fd4..709a848 100644 Binary files a/test/fixtures/reference-sprites/layouts/binary-tree/elements@3x.png and b/test/fixtures/reference-sprites/layouts/binary-tree/elements@3x.png differ diff --git a/test/fixtures/reference-sprites/layouts/diagonal/elements.png b/test/fixtures/reference-sprites/layouts/diagonal/elements.png index 0e2b4cf..921a143 100644 Binary files a/test/fixtures/reference-sprites/layouts/diagonal/elements.png and b/test/fixtures/reference-sprites/layouts/diagonal/elements.png differ diff --git a/test/fixtures/reference-sprites/layouts/diagonal/elements@2x.png b/test/fixtures/reference-sprites/layouts/diagonal/elements@2x.png index 26bf2f3..831afa6 100644 Binary files a/test/fixtures/reference-sprites/layouts/diagonal/elements@2x.png and b/test/fixtures/reference-sprites/layouts/diagonal/elements@2x.png differ diff --git a/test/fixtures/reference-sprites/layouts/diagonal/elements@3x.png b/test/fixtures/reference-sprites/layouts/diagonal/elements@3x.png index fb6985d..0b8eee0 100644 Binary files a/test/fixtures/reference-sprites/layouts/diagonal/elements@3x.png and b/test/fixtures/reference-sprites/layouts/diagonal/elements@3x.png differ diff --git a/test/fixtures/reference-sprites/layouts/left-right/elements.png b/test/fixtures/reference-sprites/layouts/left-right/elements.png index 21e6420..6286e59 100644 Binary files a/test/fixtures/reference-sprites/layouts/left-right/elements.png and b/test/fixtures/reference-sprites/layouts/left-right/elements.png differ diff --git a/test/fixtures/reference-sprites/layouts/left-right/elements@2x.png b/test/fixtures/reference-sprites/layouts/left-right/elements@2x.png index 20c8e97..ceb4b6b 100644 Binary files a/test/fixtures/reference-sprites/layouts/left-right/elements@2x.png and b/test/fixtures/reference-sprites/layouts/left-right/elements@2x.png differ diff --git a/test/fixtures/reference-sprites/layouts/left-right/elements@3x.png b/test/fixtures/reference-sprites/layouts/left-right/elements@3x.png index 9b37fd4..350ce88 100644 Binary files a/test/fixtures/reference-sprites/layouts/left-right/elements@3x.png and b/test/fixtures/reference-sprites/layouts/left-right/elements@3x.png differ diff --git a/test/fixtures/reference-sprites/layouts/top-down/elements.png b/test/fixtures/reference-sprites/layouts/top-down/elements.png index 1f3f83e..465175d 100644 Binary files a/test/fixtures/reference-sprites/layouts/top-down/elements.png and b/test/fixtures/reference-sprites/layouts/top-down/elements.png differ diff --git a/test/fixtures/reference-sprites/layouts/top-down/elements@2x.png b/test/fixtures/reference-sprites/layouts/top-down/elements@2x.png index 9cb23ee..10563fd 100644 Binary files a/test/fixtures/reference-sprites/layouts/top-down/elements@2x.png and b/test/fixtures/reference-sprites/layouts/top-down/elements@2x.png differ diff --git a/test/fixtures/reference-sprites/layouts/top-down/elements@3x.png b/test/fixtures/reference-sprites/layouts/top-down/elements@3x.png index 248a7bb..96cff04 100644 Binary files a/test/fixtures/reference-sprites/layouts/top-down/elements@3x.png and b/test/fixtures/reference-sprites/layouts/top-down/elements@3x.png differ diff --git a/test/index.test.js b/test/index.test.js index 5d785f6..e23be99 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -21,15 +21,14 @@ describe('Plugin processes', function() { /* eslint-disable no-underscore-dangle */ plugin.__set__('updateReferences', updateReferences); - const run = () => { - return postcss([plugin(opts)]) - .process('', { + const run = async () => { + try { + return await postcss([plugin(opts)]).process('', { from: undefined, - }) - .then(() => {}) - .catch((err) => { - return Promise.reject(err); }); + } catch (error) { + return Promise.reject(error); + } }; expect(run()) diff --git a/test/sprites.test.js b/test/sprites.test.js index a3d66ff..75af6cb 100644 --- a/test/sprites.test.js +++ b/test/sprites.test.js @@ -55,4 +55,42 @@ describe('Build sprites', function() { done(); }); + + it('should throw exception if directory cannot be created', function(done) { + const testImages = [ + { + path: '', + url: 'images/arrow-next.png#elements', + stylesheetPath: './test/fixtures', + ratio: 1, + groups: ['elements'], + token: {}, + hash: 'elements', + }, + ]; + + const testSprites = [ + { + coordinates: { + '': {}, + }, + properties: { width: 28, height: 27 }, + image: '', + groups: ['elements'], + path: '', + isFromCache: false, + }, + ]; + + const mkdirp = () => { + return Promise.reject(new Error()); + }; + + /* eslint-disable no-underscore-dangle */ + sprites.__set__('mkdirp', mkdirp); + + expect(sprites.saveSprites(testImages, testSprites)) + .to.eventually.be.rejectedWith('could not be created') + .notify(done); + }); }); diff --git a/test/test-utils.js b/test/test-utils.js index 7f21c23..53fe0cd 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -16,19 +16,21 @@ const getTestOptions = () => { ); }; -const assertEqual = (input, output, opts, done) => { - postcss([plugin(opts)]) - .process(input, { from: undefined }) - .then((result) => { - expect(result.css).to.eql(output); - - // eslint-disable-next-line - expect(result.warnings()).to.be.empty; - done(); - }) - .catch((error) => { - done(error); +const assertEqual = async (input, output, opts, done) => { + try { + const result = await postcss([plugin(opts)]).process(input, { + from: undefined, }); + + expect(result.css).to.eql(output); + + // eslint-disable-next-line + expect(result.warnings()).to.be.empty; + + done(); + } catch (error) { + done(error); + } }; /** @@ -53,53 +55,57 @@ const getSpriteFilenames = (directory) => { const assertVisuallyEqual = (testDir, referenceDir, opts, done) => { const options = opts || getTestOptions(); - fs.readFile( - path.resolve(__dirname, 'fixtures/input.css'), - 'utf8', - (err, css) => { - postcss([plugin(options)]) - .process(css, { - from: undefined, - }) - .then(() => { - const threshold = 0.1; + /** + * Visual regression test. + * + * @param {object} err - Error callback. + * @param {object} css - CSS file object. + * + * @returns {Function} + */ + async function visualTest(err, css) { + try { + await postcss([plugin(options)]).process(css, { + from: undefined, + }); - getSpriteFilenames(testDir) - .then((values) => { - values.forEach((fileName) => { - const testImage = PNG.sync.read( - fs.readFileSync(`${testDir}/${fileName}`) - ); - const referenceImage = PNG.sync.read( - fs.readFileSync(`${referenceDir}/${fileName}`) - ); + const threshold = 0.1; - const { width, height } = referenceImage; + const values = await getSpriteFilenames(testDir); - const imageDiff = pixelmatch( - testImage.data, - referenceImage.data, - null, - width, - height, - { - threshold, - } - ); + values.forEach((fileName) => { + const testImage = PNG.sync.read( + fs.readFileSync(`${testDir}/${fileName}`) + ); + const referenceImage = PNG.sync.read( + fs.readFileSync(`${referenceDir}/${fileName}`) + ); + const { width, height } = referenceImage; + const imageDiff = pixelmatch( + testImage.data, + referenceImage.data, + null, + width, + height, + { + threshold, + } + ); - expect(imageDiff).to.be.below(threshold); - }); + expect(imageDiff).to.be.below(threshold); + }); - done(); - }) - .catch((error) => { - done(error); - }); - }) - .catch((error) => { - done(error); - }); + done(); + } catch (error) { + done(error); } + } + + fs.readFile( + path.resolve(__dirname, 'fixtures/input.css'), + 'utf8', + // eslint-disable-next-line + (err, css) => visualTest(err, css) ); };