diff --git a/.gitignore b/.gitignore index fc156669..1406785e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,5 @@ node_modules/ tmp/ *.log .idea/ -coverage/ +.nyc_output/ highlight_alias.json diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 23f6a506..00000000 --- a/.npmignore +++ /dev/null @@ -1,9 +0,0 @@ -test/ -tmp/ -coverage/ -*.log -.jshintrc -.travis.yml -gulpfile.js -.idea/ -appveyor.yml diff --git a/.travis.yml b/.travis.yml index 52672917..42cf8d2c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,16 +8,14 @@ cache: - node_modules node_js: - - "6" + - "8" + - "10" - "node" script: - # For older versions of npm (ie. the one bundled with Node 6), we need to manually run `prepare` - # to build the project. You can still install and consume the package without any issue. - - if [[ "$TRAVIS_NODE_VERSION" == "6" ]]; then npm run prepare; fi - npm run eslint - npm run test-cov after_script: - npm install coveralls - - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js + - nyc report --reporter=text-lcov | coveralls diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 9389aa1d..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -# Next - -- **[Fix]** Remove postinstall step, fixes installations issues for some systems. [#24](https://github.com/hexojs/hexo-util/issues/24) diff --git a/README.md b/README.md index b536f549..112d5ef2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # hexo-util -[![Build Status](https://travis-ci.org/hexojs/hexo-util.svg?branch=master)](https://travis-ci.org/hexojs/hexo-util) [![NPM version](https://badge.fury.io/js/hexo-util.svg)](http://badge.fury.io/js/hexo-util) [![Coverage Status](https://coveralls.io/repos/hexojs/hexo-util/badge.svg?branch=master&service=github)](https://coveralls.io/github/hexojs/hexo-util?branch=master) [![dependencies Status](https://david-dm.org/hexojs/hexo-util/status.svg)](https://david-dm.org/hexojs/hexo-util) [![devDependencies Status](https://david-dm.org/hexojs/hexo-util/dev-status.svg)](https://david-dm.org/hexojs/hexo-util?type=dev) +[![Build Status](https://travis-ci.org/hexojs/hexo-util.svg?branch=master)](https://travis-ci.org/hexojs/hexo-util) +[![NPM version](https://badge.fury.io/js/hexo-util.svg)](https://www.npmjs.com/package/hexo-util) +[![Coverage Status](https://coveralls.io/repos/hexojs/hexo-util/badge.svg?branch=master&service=github)](https://coveralls.io/github/hexojs/hexo-util?branch=master) +[![dependencies Status](https://david-dm.org/hexojs/hexo-util/status.svg)](https://david-dm.org/hexojs/hexo-util) +[![devDependencies Status](https://david-dm.org/hexojs/hexo-util/dev-status.svg)](https://david-dm.org/hexojs/hexo-util?type=dev) Utilities for [Hexo]. @@ -67,6 +71,7 @@ hash('123456'); ``` ### HashStream() +**\[deprecated\]** use `createSha1Hash()`. Generates SHA1 hash with a transform stream. @@ -80,6 +85,18 @@ fs.createReadStream('/path/to/file') }); ``` +### createSha1Hash() +return SHA1 hash object. + This is the same as calling `createHash('utf8')` in the node.js native module crypto. + ``` js +const sha1 = createSha1Hash(); + fs.createReadStream('/path/to/file') + .pipe(sha1) + .on('finish', () => { + console.log(sha1.read()); + }); +``` + ### highlight(str, [options]) Syntax highlighting for a code block. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..0846e741 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,36 @@ +# Fix line endings in Windows. (runs before repo cloning) +init: + - git config --global core.autocrlf input + +# Test against these versions of Node.js. +environment: + matrix: + - nodejs_version: "8" + - nodejs_version: "10" + - nodejs_version: "12" + +matrix: + fast_finish: true + +# Install scripts. (runs after repo cloning) +install: + - ps: Install-Product node $env:nodejs_version + - npm install -g npm + - npm install + +cache: + - node_modules -> package.json + +# Post-install test scripts. +test_script: + # Output useful info for debugging. + - node --version + - npm --version + # Run tests + - npm test + +# Don't actually build. +build: off + +# Set build version format here instead of in the admin panel. +version: "{build}" diff --git a/lib/cache_stream.js b/lib/cache_stream.js index 640d9412..91e65124 100644 --- a/lib/cache_stream.js +++ b/lib/cache_stream.js @@ -1,6 +1,6 @@ 'use strict'; -var Transform = require('stream').Transform; +const { Transform } = require('stream'); function CacheStream() { Transform.call(this); @@ -11,7 +11,7 @@ function CacheStream() { require('util').inherits(CacheStream, Transform); CacheStream.prototype._transform = function(chunk, enc, callback) { - var buf = chunk instanceof Buffer ? chunk : Buffer.from(chunk, enc); + const buf = chunk instanceof Buffer ? chunk : Buffer.from(chunk, enc); this._cache.push(buf); this.push(buf); diff --git a/lib/camel_case_keys.js b/lib/camel_case_keys.js index 40b0badf..55e04f3e 100644 --- a/lib/camel_case_keys.js +++ b/lib/camel_case_keys.js @@ -1,8 +1,6 @@ 'use strict'; -var camelCase = require('camel-case'); - -var rPrefixUnderscore = /^(_+)/; +const camelCase = require('camel-case'); function getter(key) { return function() { @@ -16,31 +14,37 @@ function setter(key) { }; } +function toCamelCase(str) { + let prefixLength = -1; + + while (str[++prefixLength] === '_'); + + if (!prefixLength) { + return camelCase(str); + } + return str.substring(0, prefixLength) + camelCase(str.substring(prefixLength)); +} + function camelCaseKeys(obj) { if (typeof obj !== 'object') throw new TypeError('obj must be an object!'); - var keys = Object.keys(obj); - var result = {}; + const keys = Object.keys(obj); + const { length } = keys; + const result = {}; - for (var i = 0, len = keys.length; i < len; i++) { - var key = keys[i]; - var value = obj[key]; - var match = key.match(rPrefixUnderscore); - var newKey; + for (let i = 0; i < length; i++) { + const oldKey = keys[i]; + const newKey = toCamelCase(oldKey); - if (match) { - var underscore = match[1]; - newKey = underscore + camelCase(key.substring(underscore.length)); - } else { - newKey = camelCase(key); - } + result[newKey] = obj[oldKey]; - if (newKey === key) { - result[key] = value; - } else { - result[newKey] = value; - result.__defineGetter__(key, getter(newKey)); - result.__defineSetter__(key, setter(newKey)); + if (newKey !== oldKey) { + Object.defineProperty(result, oldKey, { + get: getter(newKey), + set: setter(newKey), + configurable: true, + enumerable: true + }); } } diff --git a/lib/color.js b/lib/color.js new file mode 100644 index 00000000..0cae20d0 --- /dev/null +++ b/lib/color.js @@ -0,0 +1,336 @@ +'use strict'; + +// https://github.com/imathis/hsl-picker/blob/master/assets/javascripts/modules/color.coffee +const rHex3 = /^#[0-9a-f]{3}$/; +const rHex6 = /^#[0-9a-f]{6}$/; +const rRGB = /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,?\s*(0?\.?\d+)?\s*\)$/; +const rHSL = /^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*,?\s*(0?\.?\d+)?\s*\)$/; + +// https://www.w3.org/TR/css3-color/#svg-color +const colorNames = { + aliceblue: {r: 240, g: 248, b: 255, a: 1}, + antiquewhite: {r: 250, g: 235, b: 215, a: 1}, + aqua: {r: 0, g: 255, b: 255, a: 1}, + aquamarine: {r: 127, g: 255, b: 212, a: 1}, + azure: {r: 240, g: 255, b: 255, a: 1}, + beige: {r: 245, g: 245, b: 220, a: 1}, + bisque: {r: 255, g: 228, b: 196, a: 1}, + black: {r: 0, g: 0, b: 0, a: 1}, + blanchedalmond: {r: 255, g: 235, b: 205, a: 1}, + blue: {r: 0, g: 0, b: 255, a: 1}, + blueviolet: {r: 138, g: 43, b: 226, a: 1}, + brown: {r: 165, g: 42, b: 42, a: 1}, + burlywood: {r: 222, g: 184, b: 135, a: 1}, + cadetblue: {r: 95, g: 158, b: 160, a: 1}, + chartreuse: {r: 127, g: 255, b: 0, a: 1}, + chocolate: {r: 210, g: 105, b: 30, a: 1}, + coral: {r: 255, g: 127, b: 80, a: 1}, + cornflowerblue: {r: 100, g: 149, b: 237, a: 1}, + cornsilk: {r: 255, g: 248, b: 220, a: 1}, + crimson: {r: 220, g: 20, b: 60, a: 1}, + cyan: {r: 0, g: 255, b: 255, a: 1}, + darkblue: {r: 0, g: 0, b: 139, a: 1}, + darkcyan: {r: 0, g: 139, b: 139, a: 1}, + darkgoldenrod: {r: 184, g: 134, b: 11, a: 1}, + darkgray: {r: 169, g: 169, b: 169, a: 1}, + darkgreen: {r: 0, g: 100, b: 0, a: 1}, + darkgrey: {r: 169, g: 169, b: 169, a: 1}, + darkkhaki: {r: 189, g: 183, b: 107, a: 1}, + darkmagenta: {r: 139, g: 0, b: 139, a: 1}, + darkolivegreen: {r: 85, g: 107, b: 47, a: 1}, + darkorange: {r: 255, g: 140, b: 0, a: 1}, + darkorchid: {r: 153, g: 50, b: 204, a: 1}, + darkred: {r: 139, g: 0, b: 0, a: 1}, + darksalmon: {r: 233, g: 150, b: 122, a: 1}, + darkseagreen: {r: 143, g: 188, b: 143, a: 1}, + darkslateblue: {r: 72, g: 61, b: 139, a: 1}, + darkslategray: {r: 47, g: 79, b: 79, a: 1}, + darkslategrey: {r: 47, g: 79, b: 79, a: 1}, + darkturquoise: {r: 0, g: 206, b: 209, a: 1}, + darkviolet: {r: 148, g: 0, b: 211, a: 1}, + deeppink: {r: 255, g: 20, b: 147, a: 1}, + deepskyblue: {r: 0, g: 191, b: 255, a: 1}, + dimgray: {r: 105, g: 105, b: 105, a: 1}, + dimgrey: {r: 105, g: 105, b: 105, a: 1}, + dodgerblue: {r: 30, g: 144, b: 255, a: 1}, + firebrick: {r: 178, g: 34, b: 34, a: 1}, + floralwhite: {r: 255, g: 250, b: 240, a: 1}, + forestgreen: {r: 34, g: 139, b: 34, a: 1}, + fuchsia: {r: 255, g: 0, b: 255, a: 1}, + gainsboro: {r: 220, g: 220, b: 220, a: 1}, + ghostwhite: {r: 248, g: 248, b: 255, a: 1}, + gold: {r: 255, g: 215, b: 0, a: 1}, + goldenrod: {r: 218, g: 165, b: 32, a: 1}, + gray: {r: 128, g: 128, b: 128, a: 1}, + green: {r: 0, g: 128, b: 0, a: 1}, + greenyellow: {r: 173, g: 255, b: 47, a: 1}, + grey: {r: 128, g: 128, b: 128, a: 1}, + honeydew: {r: 240, g: 255, b: 240, a: 1}, + hotpink: {r: 255, g: 105, b: 180, a: 1}, + indianred: {r: 205, g: 92, b: 92, a: 1}, + indigo: {r: 75, g: 0, b: 130, a: 1}, + ivory: {r: 255, g: 255, b: 240, a: 1}, + khaki: {r: 240, g: 230, b: 140, a: 1}, + lavender: {r: 230, g: 230, b: 250, a: 1}, + lavenderblush: {r: 255, g: 240, b: 245, a: 1}, + lawngreen: {r: 124, g: 252, b: 0, a: 1}, + lemonchiffon: {r: 255, g: 250, b: 205, a: 1}, + lightblue: {r: 173, g: 216, b: 230, a: 1}, + lightcoral: {r: 240, g: 128, b: 128, a: 1}, + lightcyan: {r: 224, g: 255, b: 255, a: 1}, + lightgoldenrodyellow: {r: 250, g: 250, b: 210, a: 1}, + lightgray: {r: 211, g: 211, b: 211, a: 1}, + lightgreen: {r: 144, g: 238, b: 144, a: 1}, + lightgrey: {r: 211, g: 211, b: 211, a: 1}, + lightpink: {r: 255, g: 182, b: 193, a: 1}, + lightsalmon: {r: 255, g: 160, b: 122, a: 1}, + lightseagreen: {r: 32, g: 178, b: 170, a: 1}, + lightskyblue: {r: 135, g: 206, b: 250, a: 1}, + lightslategray: {r: 119, g: 136, b: 153, a: 1}, + lightslategrey: {r: 119, g: 136, b: 153, a: 1}, + lightsteelblue: {r: 176, g: 196, b: 222, a: 1}, + lightyellow: {r: 255, g: 255, b: 224, a: 1}, + lime: {r: 0, g: 255, b: 0, a: 1}, + limegreen: {r: 50, g: 205, b: 50, a: 1}, + linen: {r: 250, g: 240, b: 230, a: 1}, + magenta: {r: 255, g: 0, b: 255, a: 1}, + maroon: {r: 128, g: 0, b: 0, a: 1}, + mediumaquamarine: {r: 102, g: 205, b: 170, a: 1}, + mediumblue: {r: 0, g: 0, b: 205, a: 1}, + mediumorchid: {r: 186, g: 85, b: 211, a: 1}, + mediumpurple: {r: 147, g: 112, b: 219, a: 1}, + mediumseagreen: {r: 60, g: 179, b: 113, a: 1}, + mediumslateblue: {r: 123, g: 104, b: 238, a: 1}, + mediumspringgreen: {r: 0, g: 250, b: 154, a: 1}, + mediumturquoise: {r: 72, g: 209, b: 204, a: 1}, + mediumvioletred: {r: 199, g: 21, b: 133, a: 1}, + midnightblue: {r: 25, g: 25, b: 112, a: 1}, + mintcream: {r: 245, g: 255, b: 250, a: 1}, + mistyrose: {r: 255, g: 228, b: 225, a: 1}, + moccasin: {r: 255, g: 228, b: 181, a: 1}, + navajowhite: {r: 255, g: 222, b: 173, a: 1}, + navy: {r: 0, g: 0, b: 128, a: 1}, + oldlace: {r: 253, g: 245, b: 230, a: 1}, + olive: {r: 128, g: 128, b: 0, a: 1}, + olivedrab: {r: 107, g: 142, b: 35, a: 1}, + orange: {r: 255, g: 165, b: 0, a: 1}, + orangered: {r: 255, g: 69, b: 0, a: 1}, + orchid: {r: 218, g: 112, b: 214, a: 1}, + palegoldenrod: {r: 238, g: 232, b: 170, a: 1}, + palegreen: {r: 152, g: 251, b: 152, a: 1}, + paleturquoise: {r: 175, g: 238, b: 238, a: 1}, + palevioletred: {r: 219, g: 112, b: 147, a: 1}, + papayawhip: {r: 255, g: 239, b: 213, a: 1}, + peachpuff: {r: 255, g: 218, b: 185, a: 1}, + peru: {r: 205, g: 133, b: 63, a: 1}, + pink: {r: 255, g: 192, b: 203, a: 1}, + plum: {r: 221, g: 160, b: 221, a: 1}, + powderblue: {r: 176, g: 224, b: 230, a: 1}, + purple: {r: 128, g: 0, b: 128, a: 1}, + red: {r: 255, g: 0, b: 0, a: 1}, + rosybrown: {r: 188, g: 143, b: 143, a: 1}, + royalblue: {r: 65, g: 105, b: 225, a: 1}, + saddlebrown: {r: 139, g: 69, b: 19, a: 1}, + salmon: {r: 250, g: 128, b: 114, a: 1}, + sandybrown: {r: 244, g: 164, b: 96, a: 1}, + seagreen: {r: 46, g: 139, b: 87, a: 1}, + seashell: {r: 255, g: 245, b: 238, a: 1}, + sienna: {r: 160, g: 82, b: 45, a: 1}, + silver: {r: 192, g: 192, b: 192, a: 1}, + skyblue: {r: 135, g: 206, b: 235, a: 1}, + slateblue: {r: 106, g: 90, b: 205, a: 1}, + slategray: {r: 112, g: 128, b: 144, a: 1}, + slategrey: {r: 112, g: 128, b: 144, a: 1}, + snow: {r: 255, g: 250, b: 250, a: 1}, + springgreen: {r: 0, g: 255, b: 127, a: 1}, + steelblue: {r: 70, g: 130, b: 180, a: 1}, + tan: {r: 210, g: 180, b: 140, a: 1}, + teal: {r: 0, g: 128, b: 128, a: 1}, + thistle: {r: 216, g: 191, b: 216, a: 1}, + tomato: {r: 255, g: 99, b: 71, a: 1}, + turquoise: {r: 64, g: 224, b: 208, a: 1}, + violet: {r: 238, g: 130, b: 238, a: 1}, + wheat: {r: 245, g: 222, b: 179, a: 1}, + white: {r: 255, g: 255, b: 255, a: 1}, + whitesmoke: {r: 245, g: 245, b: 245, a: 1}, + yellow: {r: 255, g: 255, b: 0, a: 1}, + yellowgreen: {r: 154, g: 205, b: 50, a: 1} +}; + +const convertHue = (p, q, h) => { + if (h < 0) h++; + if (h > 1) h--; + + let color; + + if (h * 6 < 1) { + color = p + ((q - p) * h * 6); + } else if (h * 2 < 1) { + color = q; + } else if (h * 3 < 2) { + color = p + ((q - p) * ((2 / 3) - h) * 6); + } else { + color = p; + } + + return Math.round(color * 255); +}; + +const convertRGB = value => { + const str = value.toString(16); + if (value < 16) return `0${str}`; + + return str; +}; + +const mixValue = (a, b, ratio) => a + ((b - a) * ratio); + +class Color { + + /** + * @param {string|{ r: number; g: number; b: number; a: number;}} color + */ + constructor(color) { + if (typeof color === 'string') { + this._parse(color); + } else if (color != null && typeof color === 'object') { + this.r = color.r | 0; + this.g = color.g | 0; + this.b = color.b | 0; + this.a = +color.a; + } else { + throw new TypeError('color is required!'); + } + + if (this.r < 0 || this.r > 255 + || this.g < 0 || this.g > 255 + || this.b < 0 || this.b > 255 + || this.a < 0 || this.a > 1) { + throw new RangeError(`{r: ${this.r}, g: ${this.g}, b: ${this.b}, a: ${this.a}} is invalid.`); + } + } + + /** + * @param {string} color + */ + _parse(color) { + color = color.toLowerCase(); + + if (Object.prototype.hasOwnProperty.call(colorNames, color)) { + const obj = colorNames[color]; + + this.r = obj.r; + this.g = obj.g; + this.b = obj.b; + this.a = obj.a; + + return; + } + + if (rHex3.test(color)) { + const txt = color.substring(1); + const code = parseInt(txt, 16); + + this.r = ((code & 0xF00) >> 8) * 17; + this.g = ((code & 0xF0) >> 4) * 17; + this.b = (code & 0xF) * 17; + this.a = 1; + + return; + } + + if (rHex6.test(color)) { + const txt = color.substring(1); + const code = parseInt(txt, 16); + + this.r = (code & 0xFF0000) >> 16; + this.g = (code & 0xFF00) >> 8; + this.b = code & 0xFF; + this.a = 1; + + return; + } + + let match = color.match(rRGB); + + if (match) { + this.r = match[1] | 0; + this.g = match[2] | 0; + this.b = match[3] | 0; + this.a = match[4] ? +match[4] : 1; + + return; + } + + match = color.match(rHSL); + + if (match) { + const h = +match[1] / 360; + const s = +match[2] / 100; + const l = +match[3] / 100; + + this.a = match[4] ? +match[4] : 1; + + if (!s) { + this.r = this.g = this.b = l * 255; + } + + const q = l < 0.5 ? l * (1 + s) : l + s - (l * s); + const p = (2 * l) - q; + + const rt = h + (1 / 3); + const gt = h; + const bt = h - (1 / 3); + + this.r = convertHue(p, q, rt); + this.g = convertHue(p, q, gt); + this.b = convertHue(p, q, bt); + + return; + } + + throw new Error(`${color} is not a supported color format.`); + } + + toString() { + if (this.a === 1) { + const r = convertRGB(this.r); + const g = convertRGB(this.g); + const b = convertRGB(this.b); + + if (this.r % 17 || this.g % 17 || this.b % 17) { + return `#${r}${g}${b}`; + } + + return `#${r[0]}${g[0]}${b[0]}`; + } + + return `rgba(${this.r}, ${this.g}, ${this.b}, ${parseFloat(this.a.toFixed(2))})`; + } + + /** + * @param {string|{ r: number; g: number; b: number; a: number;}} color + * @param {number} ratio + */ + mix(color, ratio) { + if (ratio > 1 || ratio < 0) { + throw new RangeError('Valid numbers is only between 0 and 1.'); + } + switch (ratio) { + case 0: + return new Color(this); + + case 1: + return new Color(color); + } + + return new Color({ + r: Math.round(mixValue(this.r, color.r, ratio)), + g: Math.round(mixValue(this.g, color.g, ratio)), + b: Math.round(mixValue(this.b, color.b, ratio)), + a: mixValue(this.a, color.a, ratio) + }); + } +} + +module.exports = Color; diff --git a/lib/escape_diacritic.js b/lib/escape_diacritic.js index 2b39d827..5e94465d 100644 --- a/lib/escape_diacritic.js +++ b/lib/escape_diacritic.js @@ -1,6 +1,6 @@ 'use strict'; -var defaultDiacriticsRemovalap = [ +const defaultDiacriticsRemovalap = [ {'base': 'A', 'letters': '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F'}, {'base': 'AA', 'letters': '\uA732'}, {'base': 'AE', 'letters': '\u00C6\u01FC\u01E2'}, @@ -89,12 +89,12 @@ var defaultDiacriticsRemovalap = [ {'base': 'z', 'letters': '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763'} ]; -var diacriticsMap = {}; +const diacriticsMap = {}; -for (var i = 0; i < defaultDiacriticsRemovalap.length; i++) { - var letters = defaultDiacriticsRemovalap[i].letters.split(''); +for (let i = 0; i < defaultDiacriticsRemovalap.length; i++) { + const letters = defaultDiacriticsRemovalap[i].letters.split(''); - for (var j = 0; j < letters.length; j++) { + for (let j = 0; j < letters.length; j++) { diacriticsMap[letters[j]] = defaultDiacriticsRemovalap[i].base; } } @@ -104,9 +104,7 @@ function escapeDiacritic(str) { // http://stackoverflow.com/a/18391901 // eslint-disable-next-line no-control-regex - return str.replace(/[^\u0000-\u007E]/g, function(a) { - return diacriticsMap[a] || a; - }); + return str.replace(/[^\u0000-\u007E]/g, a => diacriticsMap[a] || a); } module.exports = escapeDiacritic; diff --git a/lib/escape_html.js b/lib/escape_html.js index f094eb66..8c51211b 100644 --- a/lib/escape_html.js +++ b/lib/escape_html.js @@ -1,6 +1,6 @@ 'use strict'; -var htmlEntityMap = { +const htmlEntityMap = { '&': '&', '<': '<', '>': '>', @@ -13,9 +13,7 @@ function escapeHTML(str) { if (typeof str !== 'string') throw new TypeError('str must be a string!'); // http://stackoverflow.com/a/12034334 - return str.replace(/[&<>"'/]/g, function(a) { - return htmlEntityMap[a]; - }); + return str.replace(/[&<>"'/]/g, a => htmlEntityMap[a]); } module.exports = escapeHTML; diff --git a/lib/hash.js b/lib/hash.js index e48f0ee2..57a1547e 100644 --- a/lib/hash.js +++ b/lib/hash.js @@ -1,25 +1,27 @@ 'use strict'; -var Stream = require('stream'); -var Transform = Stream.Transform; -var crypto = require('crypto'); +const { Transform } = require('stream'); +const crypto = require('crypto'); -var ALGORITHM = 'sha1'; +const ALGORITHM = 'sha1'; -function HashStream() { - Transform.call(this, { - objectMode: true - }); +function createSha1Hash() { + return crypto.createHash(ALGORITHM); +} - this._hash = crypto.createHash(ALGORITHM); +/** + * @deprecated + * createHash() is stream class. + */ +function HashStream() { + Transform.call(this); + this._hash = createSha1Hash(); } require('util').inherits(HashStream, Transform); HashStream.prototype._transform = function(chunk, enc, callback) { - var buffer = chunk instanceof Buffer ? chunk : Buffer.from(chunk, enc); - - this._hash.update(buffer); + this._hash.update(chunk); callback(); }; @@ -28,10 +30,11 @@ HashStream.prototype._flush = function(callback) { callback(); }; -exports.hash = function(content) { - var hash = crypto.createHash(ALGORITHM); +exports.hash = content => { + const hash = createSha1Hash(); hash.update(content); return hash.digest(); }; exports.HashStream = HashStream; +exports.createSha1Hash = createSha1Hash; diff --git a/lib/highlight.js b/lib/highlight.js index 6e7d5fd7..0ed2da4d 100644 --- a/lib/highlight.js +++ b/lib/highlight.js @@ -1,72 +1,71 @@ 'use strict'; -var hljs = require('highlight.js'); -var Entities = require('html-entities').XmlEntities; -var entities = new Entities(); -var alias = require('../highlight_alias.json'); +const hljs = require('highlight.js'); +const Entities = require('html-entities').XmlEntities; +const entities = new Entities(); +const alias = require('../highlight_alias.json'); -function highlightUtil(str, options) { +function highlightUtil(str, options = {}) { if (typeof str !== 'string') throw new TypeError('str must be a string!'); - options = options || {}; - var useHljs = options.hasOwnProperty('hljs') ? options.hljs : false; - var gutter = options.hasOwnProperty('gutter') ? options.gutter : true; - var wrap = options.hasOwnProperty('wrap') ? options.wrap : true; - var firstLine = options.hasOwnProperty('firstLine') ? +options.firstLine : 1; - var caption = options.caption; - var mark = options.hasOwnProperty('mark') ? options.mark : []; - var tab = options.tab; + const useHljs = Object.prototype.hasOwnProperty.call(options, 'hljs') ? options.hljs : false; + const { + gutter = true, + firstLine = 1, + caption, + mark = [], + tab + } = options; + let { wrap = true } = options; hljs.configure({ classPrefix: useHljs ? 'hljs-' : ''}); - var data = highlight(str, options); + const data = highlight(str, options); if (useHljs && !gutter) wrap = false; - var before = useHljs ? '
' : '
';
-  var after = useHljs ? '
' : '
'; + const before = useHljs ? `
` : '
';
+  const after = useHljs ? '
' : '
'; if (!wrap) return useHljs ? before + data.value + after : data.value; - var lines = data.value.split('\n'); - var numbers = ''; - var content = ''; - var result = ''; - var line; + const lines = data.value.split('\n'); + let numbers = ''; + let content = ''; - for (var i = 0, len = lines.length; i < len; i++) { - line = lines[i]; + for (let i = 0, len = lines.length; i < len; i++) { + let line = lines[i]; if (tab) line = replaceTabs(line, tab); - numbers += '' + (firstLine + i) + '
'; - content += formatLine(line, firstLine + i, mark, options); + numbers += `${Number(firstLine) + i}
`; + content += formatLine(line, Number(firstLine) + i, mark, options); } - result += '
'; + let result = `
`; if (caption) { - result += '
' + caption + '
'; + result += `
${caption}
`; } result += ''; if (gutter) { - result += ''; + result += ``; } - result += ''; + result += ``; result += '
' + numbers + '
${numbers}
' + before + content + after + '${before}${content}${after}
'; return result; } function formatLine(line, lineno, marked, options) { - var useHljs = options.hljs || false; - var res = useHljs ? '' : '' + line + '' : ' marked">' + line + ''; + res += useHljs ? `${line}` : ` marked">${line}`; } else { - res += useHljs ? line : '">' + line + ''; + res += useHljs ? line : `">${line}`; } res += '
'; @@ -78,10 +77,10 @@ function encodePlainString(str) { } function replaceTabs(str, tab) { - return str.replace(/^\t+/, function(match) { - var result = ''; + return str.replace(/^\t+/, match => { + let result = ''; - for (var i = 0, len = match.length; i < len; i++) { + for (let i = 0, len = match.length; i < len; i++) { result += tab; } @@ -90,22 +89,19 @@ function replaceTabs(str, tab) { } function highlight(str, options) { - var lang = options.lang; - var autoDetect = options.hasOwnProperty('autoDetect') ? options.autoDetect : false; + let { lang } = options; + const { autoDetect = false } = options; if (!lang && autoDetect) { - lang = (function() { - var result = hljs.highlightAuto(str); - if (result.relevance > 0 && result.language) return result.language; - - }()); + const result = hljs.highlightAuto(str); + if (result.relevance > 0 && result.language) lang = result.language; } if (!lang) { lang = 'plain'; } - var result = { + const result = { value: encodePlainString(str), language: lang.toLowerCase() }; @@ -126,11 +122,11 @@ function highlight(str, options) { function tryHighlight(str, lang) { try { - var matching = str.match(/(\r?\n)/); - var separator = matching ? matching[1] : ''; - var lines = matching ? str.split(separator) : [str]; - var result = hljs.highlight(lang, lines.shift()); - var html = result.value; + const matching = str.match(/(\r?\n)/); + const separator = matching ? matching[1] : ''; + const lines = matching ? str.split(separator) : [str]; + let result = hljs.highlight(lang, lines.shift()); + let html = result.value; while (lines.length > 0) { result = hljs.highlight(lang, lines.shift(), false, result.top); html += separator + result.value; diff --git a/lib/html_tag.js b/lib/html_tag.js index 173f9077..8c7541f2 100644 --- a/lib/html_tag.js +++ b/lib/html_tag.js @@ -3,13 +3,13 @@ function htmlTag(tag, attrs, text) { if (!tag) throw new TypeError('tag is required!'); - var result = '<' + tag; + let result = `<${tag}`; - for (var i in attrs) { - if (attrs[i]) result += ' ' + i + '="' + attrs[i] + '"'; + for (const i in attrs) { + if (attrs[i] != null) result += ` ${i}="${attrs[i]}"`; } - result += text == null ? '>' : '>' + text + ''; + result += text == null ? '>' : `>${text}`; return result; } diff --git a/lib/index.js b/lib/index.js index eb8fd2ea..f38eac88 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,6 +1,6 @@ 'use strict'; -var hash = require('./hash'); +const hash = require('./hash'); exports.escapeDiacritic = require('./escape_diacritic'); exports.escapeHTML = require('./escape_html'); @@ -16,5 +16,6 @@ exports.truncate = require('./truncate'); exports.wordWrap = require('./word_wrap'); exports.hash = hash.hash; exports.HashStream = hash.HashStream; +exports.createSha1Hash = hash.createSha1Hash; exports.CacheStream = require('./cache_stream'); exports.camelCaseKeys = require('./camel_case_keys'); diff --git a/lib/pattern.js b/lib/pattern.js index f9d07756..c2eecf8c 100644 --- a/lib/pattern.js +++ b/lib/pattern.js @@ -1,8 +1,8 @@ 'use strict'; -var escapeRegExp = require('./escape_regexp'); +const escapeRegExp = require('./escape_regexp'); -var rParam = /([:*])([\w?]*)?/g; +const rParam = /([:*])([\w?]*)?/g; function Pattern(rule) { if (rule instanceof Pattern) { @@ -23,18 +23,16 @@ Pattern.prototype.test = function(str) { }; function regexFilter(rule) { - return function(str) { - return str.match(rule); - }; + return str => str.match(rule); } function stringFilter(rule) { - var params = []; + const params = []; - var regex = escapeRegExp(rule) + const regex = escapeRegExp(rule) .replace(/\\([*?])/g, '$1') - .replace(rParam, function(match, operator, name) { - var str = ''; + .replace(rParam, (match, operator, name) => { + let str = ''; if (operator === '*') { str = '(.*)?'; @@ -54,15 +52,14 @@ function stringFilter(rule) { return str; }); - return function(str) { - var match = str.match(regex); + return str => { + const match = str.match(regex); if (!match) return; - var result = {}; - var name; + const result = {}; - for (var i = 0, len = match.length; i < len; i++) { - name = params[i - 1]; + for (let i = 0, len = match.length; i < len; i++) { + const name = params[i - 1]; result[i] = match[i]; if (name) result[name] = match[i]; } diff --git a/lib/permalink.js b/lib/permalink.js index 96684579..4e31353e 100644 --- a/lib/permalink.js +++ b/lib/permalink.js @@ -1,22 +1,22 @@ 'use strict'; -var escapeRegExp = require('./escape_regexp'); +const escapeRegExp = require('./escape_regexp'); -var rParam = /:(\w+)/g; +const rParam = /:(\w+)/g; function Permalink(rule, options) { if (!rule) throw new TypeError('rule is required!'); options = options || {}; - var segments = options.segments || {}; - var params = []; + const segments = options.segments || {}; + const params = []; - var regex = escapeRegExp(rule) - .replace(rParam, function(match, name) { + const regex = escapeRegExp(rule) + .replace(rParam, (match, name) => { params.push(name); - if (segments.hasOwnProperty(name)) { - var segment = segments[name]; + if (Object.prototype.hasOwnProperty.call(segments, name)) { + const segment = segments[name]; if (segment instanceof RegExp) { return segment.source; @@ -29,7 +29,7 @@ function Permalink(rule, options) { }); this.rule = rule; - this.regex = new RegExp('^' + regex + '$'); + this.regex = new RegExp(`^${regex}$`); this.params = params; } @@ -38,13 +38,13 @@ Permalink.prototype.test = function(str) { }; Permalink.prototype.parse = function(str) { - var match = str.match(this.regex); - var params = this.params; - var result = {}; + const match = str.match(this.regex); + const { params } = this; + const result = {}; if (!match) return; - for (var i = 1, len = match.length; i < len; i++) { + for (let i = 1, len = match.length; i < len; i++) { result[params[i - 1]] = match[i]; } @@ -52,9 +52,7 @@ Permalink.prototype.parse = function(str) { }; Permalink.prototype.stringify = function(data) { - return this.rule.replace(rParam, function(match, name) { - return data[name]; - }); + return this.rule.replace(rParam, (match, name) => data[name]); }; module.exports = Permalink; diff --git a/lib/slugize.js b/lib/slugize.js index 73755c46..0a749a7c 100644 --- a/lib/slugize.js +++ b/lib/slugize.js @@ -1,27 +1,26 @@ 'use strict'; -var escapeDiacritic = require('./escape_diacritic'); -var escapeRegExp = require('./escape_regexp'); +const escapeDiacritic = require('./escape_diacritic'); +const escapeRegExp = require('./escape_regexp'); // eslint-disable-next-line no-control-regex -var rControl = /[\u0000-\u001f]/g; -var rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'<>,.?/]+/g; +const rControl = /[\u0000-\u001f]/g; +const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'<>,.?/]+/g; -function slugize(str, options) { +function slugize(str, options = {}) { if (typeof str !== 'string') throw new TypeError('str must be a string!'); - options = options || {}; - var separator = options.separator || '-'; - var escapedSep = escapeRegExp(separator); + const separator = options.separator || '-'; + const escapedSep = escapeRegExp(separator); - var result = escapeDiacritic(str) + const result = escapeDiacritic(str) // Remove control characters .replace(rControl, '') // Replace special characters .replace(rSpecial, separator) // Remove continous separators - .replace(new RegExp(escapedSep + '{2,}', 'g'), separator) + .replace(new RegExp(`${escapedSep}{2,}`, 'g'), separator) // Remove prefixing and trailing separtors - .replace(new RegExp('^' + escapedSep + '+|' + escapedSep + '+$', 'g'), ''); + .replace(new RegExp(`^${escapedSep}+|${escapedSep}+$`, 'g'), ''); switch (options.transform) { case 1: diff --git a/lib/spawn.js b/lib/spawn.js index d8ebd0ad..13d2c4af 100644 --- a/lib/spawn.js +++ b/lib/spawn.js @@ -1,40 +1,39 @@ 'use strict'; -var spawn = require('cross-spawn'); -var Promise = require('bluebird'); -var CacheStream = require('./cache_stream'); +const spawn = require('cross-spawn'); +const Promise = require('bluebird'); +const CacheStream = require('./cache_stream'); -function promiseSpawn(command, args, options) { +function promiseSpawn(command, args = [], options) { if (!command) throw new TypeError('command is required!'); - if (!options && args && !Array.isArray(args)) { + if (!options && !Array.isArray(args)) { options = args; args = []; } - args = args || []; options = options || {}; - return new Promise(function(resolve, reject) { - var task = spawn(command, args, options); - var verbose = options.verbose; - var encoding = options.hasOwnProperty('encoding') ? options.encoding : 'utf8'; - var stdoutCache = new CacheStream(); - var stderrCache = new CacheStream(); + return new Promise((resolve, reject) => { + const task = spawn(command, args, options); + const verbose = options.verbose; + const { encoding = 'utf8' } = options; + const stdoutCache = new CacheStream(); + const stderrCache = new CacheStream(); if (task.stdout) { - var stdout = task.stdout.pipe(stdoutCache); + const stdout = task.stdout.pipe(stdoutCache); if (verbose) stdout.pipe(process.stdout); } if (task.stderr) { - var stderr = task.stderr.pipe(stderrCache); + const stderr = task.stderr.pipe(stderrCache); if (verbose) stderr.pipe(process.stderr); } - task.on('close', function(code) { + task.on('close', code => { if (code) { - var e = new Error(getCache(stderrCache, encoding)); + const e = new Error(getCache(stderrCache, encoding)); e.code = code; return reject(e); @@ -47,9 +46,9 @@ function promiseSpawn(command, args, options) { // Listen to exit events if neither stdout and stderr exist (inherit stdio) if (!task.stdout && !task.stderr) { - task.on('exit', function(code) { + task.on('exit', code => { if (code) { - var e = new Error('Spawn failed'); + const e = new Error('Spawn failed'); e.code = code; return reject(e); @@ -62,7 +61,7 @@ function promiseSpawn(command, args, options) { } function getCache(stream, encoding) { - var buf = stream.getCache(); + const buf = stream.getCache(); stream.destroy(); if (!encoding) return buf; diff --git a/lib/truncate.js b/lib/truncate.js index 50775712..0dbd1dac 100644 --- a/lib/truncate.js +++ b/lib/truncate.js @@ -1,24 +1,22 @@ 'use strict'; -function truncate(str, options) { +function truncate(str, options = {}) { if (typeof str !== 'string') throw new TypeError('str must be a string!'); - options = options || {}; - var length = options.length || 30; - var omission = options.omission || '...'; - var separator = options.separator; - var omissionLength = omission.length; + const length = options.length || 30; + const omission = options.omission || '...'; + const { separator } = options; + const omissionLength = omission.length; if (str.length < length) return str; if (separator) { - var words = str.split(separator); - var word = ''; - var result = ''; - var resultLength = 0; + const words = str.split(separator); + let result = ''; + let resultLength = 0; - for (var i = 0, len = words.length; i < len; i++) { - word = words[i]; + for (let i = 0, len = words.length; i < len; i++) { + const word = words[i]; if (resultLength + word.length + omissionLength < length) { result += word + separator; diff --git a/lib/word_wrap.js b/lib/word_wrap.js index 9a552727..23fb6df6 100644 --- a/lib/word_wrap.js +++ b/lib/word_wrap.js @@ -1,17 +1,15 @@ 'use strict'; // https://github.com/rails/rails/blob/v4.2.0/actionview/lib/action_view/helpers/text_helper.rb#L240 -function wordWrap(str, options) { +function wordWrap(str, options = {}) { if (typeof str !== 'string') throw new TypeError('str must be a string!'); - options = options || {}; - var width = options.width || 80; - var regex = new RegExp('(.{1,' + width + '})(\\s+|$)', 'g'); - var lines = str.split('\n'); - var line = ''; + const width = options.width || 80; + const regex = new RegExp(`(.{1,${width}})(\\s+|$)`, 'g'); + const lines = str.split('\n'); - for (var i = 0, len = lines.length; i < len; i++) { - line = lines[i]; + for (let i = 0, len = lines.length; i < len; i++) { + const line = lines[i]; if (line.length > width) { lines[i] = line.replace(regex, '$1\n').trim(); @@ -22,4 +20,3 @@ function wordWrap(str, options) { } module.exports = wordWrap; - diff --git a/package.json b/package.json index 76dd8f8d..ed599639 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,24 @@ { "name": "hexo-util", - "version": "0.6.3", + "version": "1.0.0", "description": "Utilities for Hexo.", "main": "lib/index", "scripts": { "eslint": "eslint .", "test": "mocha test/index.js", - "test-cov": "istanbul cover --print both _mocha -- test/index.js", - "build:highlight": "node scripts/build_highlight_alias.js > highlight_alias.json", + "test-cov": "nyc npm run test", + "build:highlight": "node scripts/build_highlight_alias.js", "prepare": "npm run build:highlight" }, "directories": { - "lib": "./lib" + "lib": "./lib", + "scripts": "./scripts" }, + "files": [ + "lib/", + "scripts/", + "highlight_alias.json" + ], "repository": "hexojs/hexo-util", "homepage": "https://hexo.io/", "keywords": [ @@ -26,21 +32,24 @@ ], "license": "MIT", "devDependencies": { - "chai": "^3.5.0", - "eslint": "^4.19.1", + "chai": "^4.2.0", + "chai-as-promised": "^7.1.1", + "eslint": "^6.0.1", "eslint-config-hexo": "^3.0.0", "html-tag-validator": "^1.5.0", - "istanbul": "^0.4.3", - "jscs-preset-hexo": "^1.0.1", - "mocha": "^5.1.0", - "rewire": "^2.5.1" + "mocha": "^6.0.1", + "nyc": "^14.1.1", + "rewire": "^4.0.1" }, "dependencies": { - "bluebird": "^3.4.0", + "bluebird": "^3.5.2", "camel-case": "^3.0.0", - "cross-spawn": "^4.0.0", - "highlight.js": "^9.4.0", - "html-entities": "^1.2.0", - "striptags": "^2.1.1" + "cross-spawn": "^6.0.5", + "highlight.js": "^9.13.1", + "html-entities": "^1.2.1", + "striptags": "^3.1.1" + }, + "engines": { + "node": ">=8.6.0" } } diff --git a/scripts/build_highlight_alias.js b/scripts/build_highlight_alias.js index 6f1b6184..c2e97419 100644 --- a/scripts/build_highlight_alias.js +++ b/scripts/build_highlight_alias.js @@ -1,24 +1,29 @@ 'use strict'; -var hljs = require('highlight.js'); -var languages = hljs.listLanguages(); +const hljs = require('highlight.js'); +const languages = hljs.listLanguages(); +const fs = require('fs'); -var result = { +const result = { languages: languages, aliases: {} }; -languages.forEach(function(lang) { +languages.forEach(lang => { result.aliases[lang] = lang; - var def = require('highlight.js/lib/languages/' + lang)(hljs); - var aliases = def.aliases; + const def = require('highlight.js/lib/languages/' + lang)(hljs); + const aliases = def.aliases; if (aliases) { - aliases.forEach(function(alias) { + aliases.forEach(alias => { result.aliases[alias] = lang; }); } }); -console.log(JSON.stringify(result)); +const stream = fs.createWriteStream('highlight_alias.json'); +stream.write(JSON.stringify(result)); +stream.on('end', () => { + stream.end(); +}); diff --git a/test/index.js b/test/index.js index 855b61c8..117491df 100644 --- a/test/index.js +++ b/test/index.js @@ -1,8 +1,9 @@ 'use strict'; -describe('util', function() { +describe('util', () => { require('./scripts/cache_stream'); require('./scripts/camel_case_keys'); + require('./scripts/color'); require('./scripts/escape_diacritic'); require('./scripts/escape_html'); require('./scripts/escape_regexp'); diff --git a/test/scripts/cache_stream.js b/test/scripts/cache_stream.js index 37e7bc9a..3e80262e 100644 --- a/test/scripts/cache_stream.js +++ b/test/scripts/cache_stream.js @@ -1,26 +1,28 @@ 'use strict'; -var Readable = require('stream').Readable; +require('chai').should(); -describe('CacheStream', function() { - var CacheStream = require('../../lib/cache_stream'); +const { Readable } = require('stream'); - it('default', function() { - var src = new Readable(); - var cacheStream = new CacheStream(); - var content = Buffer.from('test'); +describe('CacheStream', () => { + const CacheStream = require('../../lib/cache_stream'); + + it('default', () => { + const src = new Readable(); + const cacheStream = new CacheStream(); + const content = Buffer.from('test'); src.push(content); src.push(null); src.pipe(cacheStream); - cacheStream.on('finish', function() { + cacheStream.on('finish', () => { cacheStream.getCache().should.eql(content); }); }); - it('destroy', function() { - var cacheStream = new CacheStream(); + it('destroy', () => { + const cacheStream = new CacheStream(); cacheStream._cache = [Buffer.alloc(1)]; cacheStream.destroy(); diff --git a/test/scripts/camel_case_keys.js b/test/scripts/camel_case_keys.js index 94dc2aaf..d936e525 100644 --- a/test/scripts/camel_case_keys.js +++ b/test/scripts/camel_case_keys.js @@ -1,12 +1,12 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line +require('chai').should(); -describe('camelCaseKeys', function() { - var camelCaseKeys = require('../../lib/camel_case_keys'); +describe('camelCaseKeys', () => { + const camelCaseKeys = require('../../lib/camel_case_keys'); - it('default', function() { - var result = camelCaseKeys({ + it('default', () => { + const result = camelCaseKeys({ foo_bar: 'test' }); @@ -16,16 +16,12 @@ describe('camelCaseKeys', function() { }); }); - it('obj must be an object', function() { - try { - camelCaseKeys(); - } catch (err) { - err.should.have.property('message', 'obj must be an object!'); - } + it('obj must be an object', () => { + camelCaseKeys.should.throw('obj must be an object!'); }); - it('setter', function() { - var result = camelCaseKeys({ + it('setter', () => { + const result = camelCaseKeys({ foo_bar: 'test' }); @@ -33,8 +29,8 @@ describe('camelCaseKeys', function() { result.fooBar.should.eql('new'); }); - it('ignore prefixing underscore', function() { - var result = camelCaseKeys({ + it('ignore prefixing underscore', () => { + const result = camelCaseKeys({ _foo_bar: 'test', __bar_baz: 'foo' }); @@ -47,13 +43,8 @@ describe('camelCaseKeys', function() { }); }); - it('do nothing if the key is camelCase', function() { - var result = camelCaseKeys({ - fooBar: 'test' - }); - - result.should.eql({ - fooBar: 'test' - }); + it('do nothing if the key is camelCase', () => { + const result = camelCaseKeys({ fooBar: 'test' }); + result.should.eql({ fooBar: 'test' }); }); }); diff --git a/test/scripts/color.js b/test/scripts/color.js new file mode 100644 index 00000000..3f943fb3 --- /dev/null +++ b/test/scripts/color.js @@ -0,0 +1,55 @@ +'use strict'; + +require('chai').should(); + +describe('color', () => { + const Color = require('../../lib/color'); + + it('name', () => { + const red = new Color('red'); + const pink = new Color('pink'); + const mid1 = red.mix(pink, 1 / 3); + const mid2 = red.mix(pink, 2 / 3); + + `${red}`.should.eql('#f00'); + `${pink}`.should.eql('#ffc0cb'); + `${mid1}`.should.eql('#ff4044'); + `${mid2}`.should.eql('#ff8087'); + }); + + it('hex', () => { + const red = new Color('#f00'); + const pink = new Color('#ffc0cb'); + const mid1 = red.mix(pink, 1 / 3); + const mid2 = red.mix(pink, 2 / 3); + + `${red}`.should.eql('#f00'); + `${pink}`.should.eql('#ffc0cb'); + `${mid1}`.should.eql('#ff4044'); + `${mid2}`.should.eql('#ff8087'); + }); + + it('RGBA', () => { + const steelblueA = new Color('rgba(70, 130, 180, 0.3)'); + const steelblue = new Color('rgb(70, 130, 180)'); + const mid1 = steelblueA.mix(steelblue, 1 / 3); + const mid2 = steelblueA.mix(steelblue, 2 / 3); + + `${steelblueA}`.should.eql('rgba(70, 130, 180, 0.3)'); + `${steelblue}`.should.eql('#4682b4'); + `${mid1}`.should.eql('rgba(70, 130, 180, 0.53)'); + `${mid2}`.should.eql('rgba(70, 130, 180, 0.77)'); + }); + + it('HSLA', () => { + const steelblueA = new Color('hsla(207, 44%, 49%, 0.3)'); + const steelblue = new Color('hsl(207, 44%, 49%)'); + const mid1 = steelblueA.mix(steelblue, 1 / 3); + const mid2 = steelblueA.mix(steelblue, 2 / 3); + + `${steelblueA}`.should.eql('rgba(70, 130, 180, 0.3)'); + `${steelblue}`.should.eql('#4682b4'); + `${mid1}`.should.eql('rgba(70, 130, 180, 0.53)'); + `${mid2}`.should.eql('rgba(70, 130, 180, 0.77)'); + }); +}); diff --git a/test/scripts/escape_diacritic.js b/test/scripts/escape_diacritic.js index 225ac4d4..d8579254 100644 --- a/test/scripts/escape_diacritic.js +++ b/test/scripts/escape_diacritic.js @@ -1,19 +1,15 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line +require('chai').should(); -describe('escapeDiacritic', function() { - var escapeDiacritic = require('../../lib/escape_diacritic'); +describe('escapeDiacritic', () => { + const escapeDiacritic = require('../../lib/escape_diacritic'); - it('default', function() { + it('default', () => { escapeDiacritic('Hell\u00F2 w\u00F2rld').should.eql('Hello world'); }); - it('str must be a string', function() { - try { - escapeDiacritic(); - } catch (err) { - err.should.have.property('message', 'str must be a string!'); - } + it('str must be a string', () => { + escapeDiacritic.should.throw('str must be a string!'); }); }); diff --git a/test/scripts/escape_html.js b/test/scripts/escape_html.js index 68fc6ede..25d64841 100644 --- a/test/scripts/escape_html.js +++ b/test/scripts/escape_html.js @@ -1,19 +1,15 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line +require('chai').should(); -describe('escapeHTML', function() { - var escapeHTML = require('../../lib/escape_html'); +describe('escapeHTML', () => { + const escapeHTML = require('../../lib/escape_html'); - it('default', function() { + it('default', () => { escapeHTML('

Hello "world".

').should.eql('<p>Hello "world".</p>'); }); - it('str must be a string', function() { - try { - escapeHTML(); - } catch (err) { - err.should.have.property('message', 'str must be a string!'); - } + it('str must be a string', () => { + escapeHTML.should.throw('str must be a string!'); }); }); diff --git a/test/scripts/escape_regexp.js b/test/scripts/escape_regexp.js index f74b6deb..d9ad11b7 100644 --- a/test/scripts/escape_regexp.js +++ b/test/scripts/escape_regexp.js @@ -1,19 +1,15 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line +require('chai').should(); -describe('escapeRegExp', function() { - var escapeRegExp = require('../../lib/escape_regexp'); +describe('escapeRegExp', () => { + const escapeRegExp = require('../../lib/escape_regexp'); - it('default', function() { + it('default', () => { escapeRegExp('hello*world').should.eql('hello\\*world'); }); - it('str must be a string', function() { - try { - escapeRegExp(); - } catch (err) { - err.should.have.property('message', 'str must be a string!'); - } + it('str must be a string', () => { + escapeRegExp.should.throw('str must be a string!'); }); }); diff --git a/test/scripts/hash.js b/test/scripts/hash.js index 360e2f8a..eac02297 100644 --- a/test/scripts/hash.js +++ b/test/scripts/hash.js @@ -1,30 +1,49 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line -var crypto = require('crypto'); +require('chai').should(); +const crypto = require('crypto'); function sha1(content) { - var hash = crypto.createHash('sha1'); + const hash = crypto.createHash('sha1'); hash.update(content); return hash.digest(); } -describe('hash', function() { - var hash = require('../../lib/hash'); +describe('hash', () => { + const hash = require('../../lib/hash'); - it('hash', function() { - var content = '123456'; + it('hash', () => { + const content = '123456'; hash.hash(content).should.eql(sha1(content)); }); - it('HashStream', function() { - var content = '123456'; - var stream = new hash.HashStream(); + it('HashStream', () => { + const content = '123456'; + const stream = new hash.HashStream(); stream.write(Buffer.from(content)); stream.end(); stream.read().should.eql(sha1(content)); }); + + it('createSha1Hash', () => { + const _sha1 = hash.createSha1Hash(); + const content = '123456'; + _sha1.update(content); + _sha1.digest().should.eql(sha1(content)); + }); + + it('createSha1Hash - streamMode', () => { + const content1 = '123456'; + const content2 = '654321'; + const stream = hash.createSha1Hash(); + // explicit convert + stream.write(Buffer.from(content1)); + // implicit convert + stream.write(content2); + stream.end(); + stream.read().should.eql(sha1(content1 + content2)); + }); }); diff --git a/test/scripts/highlight.js b/test/scripts/highlight.js index 40812a32..5da3b62f 100644 --- a/test/scripts/highlight.js +++ b/test/scripts/highlight.js @@ -1,32 +1,32 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line -var hljs = require('highlight.js'); -var Entities = require('html-entities').XmlEntities; -var entities = new Entities(); -var validator = require('html-tag-validator'); +const should = require('chai').should(); // eslint-disable-line +const hljs = require('highlight.js'); +const Entities = require('html-entities').XmlEntities; +const entities = new Entities(); +const validator = require('html-tag-validator'); -var testJson = { +const testJson = { foo: 1, bar: 2 }; -var testString = JSON.stringify(testJson, null, ' '); +const testString = JSON.stringify(testJson, null, ' '); -var start = '
'; -var end = '
'; +const start = '
'; +const end = '
'; -var gutterStart = '
';
-var gutterEnd = '
'; +const gutterStart = '
';
+const gutterEnd = '
'; -var codeStart = '
';
-var codeEnd = '
'; +const codeStart = '
';
+const codeEnd = '
'; function gutter(start, end) { - var result = gutterStart; + let result = gutterStart; - for (var i = start; i <= end; i++) { - result += '' + i + '
'; + for (let i = start; i <= end; i++) { + result += `${i}
`; } result += gutterEnd; @@ -35,7 +35,7 @@ function gutter(start, end) { } function code(str, lang) { - var data; + let data; if (lang) { data = hljs.highlight(lang.toLowerCase(), str); @@ -45,32 +45,19 @@ function code(str, lang) { data = {value: entities.encode(str)}; } - var lines = data.value.split('\n'); - var result = codeStart; + const lines = data.value.split('\n'); - for (var i = 0, len = lines.length; i < len; i++) { - result += '' + lines[i] + '
'; - } - - result += codeEnd; - - return result; + return lines.reduce((prev, current) => { + return `${prev}${current}
`; + }, codeStart) + codeEnd; } -function assertResult(result) { - var expected = start; - - for (var i = 1, len = arguments.length; i < len; i++) { - expected += arguments[i]; - } - - expected += end; - - result.should.eql(expected); +function assertResult(result, ...args) { + result.should.eql(start + args.join('') + end); } function validateHtmlAsync(str, done) { - validator(str, function(err, ast) { + validator(str, (err, ast) => { if (err) { done(err); } else { @@ -79,43 +66,39 @@ function validateHtmlAsync(str, done) { }); } -describe('highlight', function() { - var highlight = require('../../lib/highlight'); +describe('highlight', () => { + const highlight = require('../../lib/highlight'); - it('default', function(done) { - var result = highlight(testString); + it('default', done => { + const result = highlight(testString); assertResult(result, gutter(1, 4), code(testString)); validateHtmlAsync(result, done); }); - it('str must be a string', function() { - try { - highlight(); - } catch (err) { - err.should.have.property('message', 'str must be a string!'); - } + it('str must be a string', () => { + highlight.should.throw('str must be a string!'); }); - it('gutter: false', function(done) { - var result = highlight(testString, {gutter: false}); + it('gutter: false', done => { + const result = highlight(testString, {gutter: false}); assertResult(result, code(testString)); validateHtmlAsync(result, done); }); - it('wrap: false', function(done) { - var result = highlight(testString, {wrap: false}); + it('wrap: false', done => { + const result = highlight(testString, {wrap: false}); result.should.eql(entities.encode(testString)); validateHtmlAsync(result, done); }); - it('firstLine', function(done) { - var result = highlight(testString, {firstLine: 3}); + it('firstLine', done => { + const result = highlight(testString, {firstLine: 3}); assertResult(result, gutter(3, 6), code(testString)); validateHtmlAsync(result, done); }); - it('lang = json', function(done) { - var result = highlight(testString, {lang: 'json'}); + it('lang = json', done => { + const result = highlight(testString, {lang: 'json'}); result.should.eql([ '
', @@ -126,8 +109,8 @@ describe('highlight', function() { validateHtmlAsync(result, done); }); - it('auto detect', function(done) { - var result = highlight(testString, {autoDetect: true}); + it('auto detect', done => { + const result = highlight(testString, {autoDetect: true}); result.should.eql([ '
', @@ -138,16 +121,16 @@ describe('highlight', function() { validateHtmlAsync(result, done); }); - it('don\'t highlight if language not found', function(done) { - var result = highlight('test', {lang: 'jrowiejrowi'}); + it('don\'t highlight if language not found', done => { + const result = highlight('test', {lang: 'jrowiejrowi'}); assertResult(result, gutter(1, 1), code('test')); validateHtmlAsync(result, done); }); it('don\'t highlight if parse failed'); - it('caption', function(done) { - var result = highlight(testString, { + it('caption', done => { + const result = highlight(testString, { caption: 'hello world' }); @@ -160,15 +143,15 @@ describe('highlight', function() { validateHtmlAsync(result, done); }); - it('tab', function(done) { - var str = [ + it('tab', done => { + const str = [ 'function fib(i){', '\tif (i <= 1) return i;', '\treturn fib(i - 1) + fib(i - 2);', '}' ].join('\n'); - var result = highlight(str, {tab: ' ', lang: 'js'}); + const result = highlight(str, {tab: ' ', lang: 'js'}); result.should.eql([ '
', @@ -179,8 +162,8 @@ describe('highlight', function() { validateHtmlAsync(result, done); }); - it('escape html entity', function(done) { - var str = [ + it('escape html entity', done => { + const str = [ 'deploy:', ' type: git', ' repo: ', @@ -188,7 +171,7 @@ describe('highlight', function() { ' message: [message]' ].join('\n'); - var result = highlight(str); + const result = highlight(str); result.should.include('<repository url>'); validateHtmlAsync(result, done); }); @@ -205,8 +188,8 @@ describe('highlight', function() { validateHtmlAsync(result, done); }); - it('parse multi-line strings correctly', function(done) { - var str = [ + it('parse multi-line strings correctly', done => { + const str = [ 'var string = `', ' Multi', ' line', @@ -214,7 +197,7 @@ describe('highlight', function() { '`' ].join('\n'); - var result = highlight(str, {lang: 'js'}); + const result = highlight(str, {lang: 'js'}); result.should.eql([ '
', gutter(1, 5), @@ -224,8 +207,8 @@ describe('highlight', function() { validateHtmlAsync(result, done); }); - it('parse multi-line strings including empty line', function(done) { - var str = [ + it('parse multi-line strings including empty line', done => { + const str = [ 'var string = `', ' Multi', '', @@ -233,7 +216,7 @@ describe('highlight', function() { '`' ].join('\n'); - var result = highlight(str, {lang: 'js'}); + const result = highlight(str, {lang: 'js'}); result.should.eql([ '
', gutter(1, 5), @@ -243,8 +226,8 @@ describe('highlight', function() { validateHtmlAsync(result, done); }); - it('auto detect of multi-line statement', function(done) { - var str = [ + it('auto detect of multi-line statement', done => { + const str = [ '"use strict";', 'var string = `', ' Multi', @@ -253,7 +236,7 @@ describe('highlight', function() { '`' ].join('\n'); - var result = highlight(str, {autoDetect: true}); + const result = highlight(str, {autoDetect: true}); result.should.eql([ '
', gutter(1, 6), @@ -263,15 +246,15 @@ describe('highlight', function() { validateHtmlAsync(result, done); }); - it('gives the highlight class to marked lines', function(done) { - var str = [ + it('gives the highlight class to marked lines', done => { + const str = [ 'roses are red', 'violets are blue', 'sugar is sweet', 'and so are you' ].join('\n'); - var result = highlight(str, {mark: [1, 3, 5]}); + const result = highlight(str, {mark: [1, 3, 5]}); result.should.include('class="line marked">roses'); result.should.include('class="line">violets'); @@ -281,14 +264,14 @@ describe('highlight', function() { }); it('hljs compatibility - with lines', (done) => { - var str = [ + const str = [ 'function (a) {', ' if (a > 3)', ' return true;', ' return false;', '}' ].join('\n'); - var result = highlight(str, {hljs: true, lang: 'javascript' }); + const result = highlight(str, {hljs: true, lang: 'javascript' }); result.should.include(gutterStart); result.should.include(codeStart); result.should.include('code class="hljs javascript"'); @@ -298,14 +281,14 @@ describe('highlight', function() { }); it('hljs compatibility - no lines', (done) => { - var str = [ + const str = [ 'function (a) {', ' if (a > 3)', ' return true;', ' return false;', '}' ].join('\n'); - var result = highlight(str, {hljs: true, gutter: false, lang: 'javascript' }); + const result = highlight(str, {hljs: true, gutter: false, lang: 'javascript' }); result.should.not.include(gutterStart); result.should.not.include(codeStart); result.should.include('code class="hljs javascript"'); diff --git a/test/scripts/html_tag.js b/test/scripts/html_tag.js index b079b81e..b719d33b 100644 --- a/test/scripts/html_tag.js +++ b/test/scripts/html_tag.js @@ -1,15 +1,15 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line +require('chai').should(); -describe('htmlTag', function() { - var htmlTag = require('../../lib/html_tag'); +describe('htmlTag', () => { + const htmlTag = require('../../lib/html_tag'); - it('tag', function() { + it('tag', () => { htmlTag('hr').should.eql('
'); }); - it('tag + attrs', function() { + it('tag + attrs', () => { htmlTag('img', { src: 'http://placekitten.com/200/300' }).should.eql(''); @@ -21,13 +21,41 @@ describe('htmlTag', function() { }).should.eql(''); }); - it('tag + attrs + text', function() { + it('tag + attrs + text', () => { htmlTag('a', { href: 'http://zespia.tw' }, 'My blog').should.eql('My blog'); }); - it('tag is required', function() { + it('tag + empty ALT attr', () => { + htmlTag('img', { + src: 'http://placekitten.com/200/300', + alt: '' + }).should.eql(''); + }); + + it('passing a zero as attribute', () => { + htmlTag('a', { + href: 'http://zespia.tw', + tabindex: 0 + }, 'My blog').should.eql('My blog'); + }); + + it('passing a null alt attribute', () => { + htmlTag('a', { + href: 'http://zespia.tw', + alt: null + }, 'My blog').should.eql('My blog'); + }); + + it('passing a undefined alt attribute', () => { + htmlTag('a', { + href: 'http://zespia.tw', + alt: undefined + }, 'My blog').should.eql('My blog'); + }); + + it('tag is required', () => { try { htmlTag(); } catch (err) { diff --git a/test/scripts/pattern.js b/test/scripts/pattern.js index c57416f2..d2e99635 100644 --- a/test/scripts/pattern.js +++ b/test/scripts/pattern.js @@ -1,13 +1,13 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line +require('chai').should(); -describe('Pattern', function() { - var Pattern = require('../../lib/pattern'); +describe('Pattern', () => { + const Pattern = require('../../lib/pattern'); - it('String - posts/:id', function() { - var pattern = new Pattern('posts/:id'); - var result = pattern.match('/posts/89'); + it('String - posts/:id', () => { + const pattern = new Pattern('posts/:id'); + const result = pattern.match('/posts/89'); result.should.eql({ 0: 'posts/89', @@ -16,9 +16,9 @@ describe('Pattern', function() { }); }); - it('String - posts/*path', function() { - var pattern = new Pattern('posts/*path'); - var result = pattern.match('posts/2013/hello-world'); + it('String - posts/*path', () => { + const pattern = new Pattern('posts/*path'); + const result = pattern.match('posts/2013/hello-world'); result.should.eql({ 0: 'posts/2013/hello-world', @@ -27,8 +27,8 @@ describe('Pattern', function() { }); }); - it('String - posts/:id?', function() { - var pattern = new Pattern('posts/:id?'); + it('String - posts/:id?', () => { + const pattern = new Pattern('posts/:id?'); pattern.match('posts/').should.eql({ 0: 'posts/', @@ -43,15 +43,15 @@ describe('Pattern', function() { }); }); - it('RegExp', function() { - var pattern = new Pattern(/ab?cd/); + it('RegExp', () => { + const pattern = new Pattern(/ab?cd/); pattern.match('abcd').should.be.ok; pattern.match('acd').should.be.ok; }); - it('Function', function() { - var pattern = new Pattern(function(str) { + it('Function', () => { + const pattern = new Pattern(str => { str.should.eql('foo'); return {}; }); @@ -59,12 +59,10 @@ describe('Pattern', function() { pattern.match('foo').should.eql({}); }); - it('rule is required', function() { - try { + it('rule is required', () => { + (() => { // eslint-disable-next-line no-new new Pattern(); - } catch (err) { - err.should.have.property('message', 'rule must be a function, a string or a regular expression.'); - } + }).should.throw('rule must be a function, a string or a regular expression.'); }); }); diff --git a/test/scripts/permalink.js b/test/scripts/permalink.js index a78717da..4ce6a6e2 100644 --- a/test/scripts/permalink.js +++ b/test/scripts/permalink.js @@ -1,12 +1,12 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line +require('chai').should(); -describe('Permalink', function() { - var Permalink = require('../../lib/permalink'); - var permalink; +describe('Permalink', () => { + const Permalink = require('../../lib/permalink'); + let permalink; - it('constructor', function() { + it('constructor', () => { permalink = new Permalink(':year/:month/:day/:title'); permalink.rule.should.eql(':year/:month/:day/:title'); @@ -26,7 +26,7 @@ describe('Permalink', function() { permalink.params.should.eql(['year', 'month', 'day', 'title']); }); - it('rule is required', function() { + it('rule is required', () => { try { // eslint-disable-next-line no-new new Permalink(); @@ -35,12 +35,12 @@ describe('Permalink', function() { } }); - it('test()', function() { + it('test()', () => { permalink.test('2014/01/31/test').should.be.true; permalink.test('foweirojwoier').should.be.false; }); - it('parse()', function() { + it('parse()', () => { permalink.parse('2014/01/31/test').should.eql({ year: '2014', month: '01', @@ -49,7 +49,7 @@ describe('Permalink', function() { }); }); - it('stringify()', function() { + it('stringify()', () => { permalink.stringify({ year: '2014', month: '01', diff --git a/test/scripts/slugize.js b/test/scripts/slugize.js index 324f859a..d1db5442 100644 --- a/test/scripts/slugize.js +++ b/test/scripts/slugize.js @@ -1,51 +1,47 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line +require('chai').should(); -describe('slugize', function() { - var slugize = require('../../lib/slugize'); +describe('slugize', () => { + const slugize = require('../../lib/slugize'); - it('spaces', function() { + it('spaces', () => { slugize('Hello World').should.eql('Hello-World'); }); - it('diacritic', function() { + it('diacritic', () => { slugize('Hell\u00F2 w\u00F2rld').should.eql('Hello-world'); }); - it('continous dashes', function() { + it('continous dashes', () => { slugize('Hello World').should.eql('Hello-World'); }); - it('prefixing and trailing dashes', function() { + it('prefixing and trailing dashes', () => { slugize('~Hello World~').should.eql('Hello-World'); }); - it('other special characters', function() { + it('other special characters', () => { slugize('Hello ~`!@#$%^&*()-_+=[]{}|\\;:"\'<>,.?/World').should.eql('Hello-World'); }); - it('custom separator', function() { + it('custom separator', () => { slugize('Hello World', {separator: '_'}).should.eql('Hello_World'); }); - it('lower case', function() { + it('lower case', () => { slugize('Hello World', {transform: 1}).should.eql('hello-world'); }); - it('upper case', function() { + it('upper case', () => { slugize('Hello World', {transform: 2}).should.eql('HELLO-WORLD'); }); - it('non-english', function() { + it('non-english', () => { slugize('遊戲').should.eql('遊戲'); }); - it('str must be a string', function() { - try { - slugize(); - } catch (err) { - err.should.have.property('message', 'str must be a string!'); - } + it('str must be a string', () => { + slugize.should.throw('str must be a string!'); }); }); diff --git a/test/scripts/spawn.js b/test/scripts/spawn.js index 4e8cb13e..7d21e909 100644 --- a/test/scripts/spawn.js +++ b/test/scripts/spawn.js @@ -1,96 +1,96 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line -var pathFn = require('path'); -var fs = require('fs'); -var rewire = require('rewire'); - -describe('spawn', function() { - var spawn = require('../../lib/spawn'); - var CacheStream = require('../../lib/cache_stream'); - var fixturePath = pathFn.join(__dirname, 'spawn_test.txt'); - var fixture = 'test content'; - - before(function(done) { - fs.writeFile(fixturePath, fixture, done); +require('chai').use(require('chai-as-promised')).should(); +const { join } = require('path'); +const { writeFile, unlink } = require('fs'); +const rewire = require('rewire'); + +const isWindows = process.platform === 'win32'; +const catCommand = isWindows ? 'type' : 'cat'; + +describe('spawn', () => { + const spawn = require('../../lib/spawn'); + const CacheStream = require('../../lib/cache_stream'); + const fixturePath = join(__dirname, 'spawn_test.txt'); + const fixture = 'test content'; + + before(done => { + writeFile(fixturePath, fixture, done); }); - after(function(done) { - fs.unlink(fixturePath, done); + after(done => { + unlink(fixturePath, done); }); - it('default', function() { - return spawn('cat', [fixturePath]).then(function(content) { - content.should.eql(fixture); - }); - }); + it('default', () => spawn(catCommand, [fixturePath]).should.become(fixture)); - it('command is required', function() { - try { - spawn(); - } catch (err) { - err.should.have.property('message', 'command is required!'); - } + it('command is required', () => { + spawn.should.throw('command is required!'); }); - it('error', function() { - return spawn('cat', ['nothing']).catch(function(err) { - err.message.trim().should.eql('cat: nothing: No such file or directory'); - err.code.should.eql(1); - }); + it('error', () => { + const promise = spawn(catCommand, ['nothing']); + if (isWindows) { + return promise.should.rejectedWith('spawn type ENOENT').and.eventually.have.property('code', 'ENOENT'); + } + return promise.should.rejectedWith('cat: nothing: No such file or directory').and.eventually.have.property('code', 1); }); - it('verbose - stdout', function() { - var spawn = rewire('../../lib/spawn'); - var stdoutCache = new CacheStream(); - var stderrCache = new CacheStream(); - var content = 'something'; + it('verbose - stdout', () => { + const spawn = rewire('../../lib/spawn'); + const stdoutCache = new CacheStream(); + const stderrCache = new CacheStream(); + const content = 'something'; - spawn.__set__('process', { + spawn.__set__('process', Object.assign({}, process, { stdout: stdoutCache, stderr: stderrCache - }); + })); return spawn('echo', [content], { verbose: true - }).then(function() { - stdoutCache.getCache().toString('utf8').trim().should.eql(content); + }).then(() => { + const result = stdoutCache.getCache().toString('utf8').trim(); + if (isWindows) { + result.should.match(new RegExp(`^(["']?)${content}\\1$`)); + } else { + result.should.eql(content); + } }); }); - it('verbose - stderr', function() { - var spawn = rewire('../../lib/spawn'); - var stdoutCache = new CacheStream(); - var stderrCache = new CacheStream(); + it('verbose - stderr', () => { + const spawn = rewire('../../lib/spawn'); + const stdoutCache = new CacheStream(); + const stderrCache = new CacheStream(); - spawn.__set__('process', { + spawn.__set__('process', Object.assign({}, process, { stdout: stdoutCache, - stderr: stderrCache - }); + stderr: stderrCache, + removeListener: () => {}, + on: () => {} + })); - return spawn('cat', ['nothing'], { + return spawn(catCommand, ['nothing'], { verbose: true - }).catch(function() { - stderrCache.getCache().toString('utf8').trim().should - .eql('cat: nothing: No such file or directory'); + }).should.rejected.then(() => { + const stderrResult = stderrCache.getCache(); + if (isWindows) { + // utf8 support in windows shell (cmd.exe) is difficult. + Buffer.byteLength(stderrResult, 'hex').should.least(1); + } else { + stderrResult.toString('utf8').should.with.match(/^cat: nothing: No such file or directory\n?$/); + } }); }); - it('custom encoding', function() { - return spawn('cat', [fixturePath], {encoding: 'hex'}).then(function(content) { - content.should.eql(Buffer.from(fixture).toString('hex')); - }); + it('custom encoding', () => { + return spawn(catCommand, [fixturePath], {encoding: 'hex'}).should.become(Buffer.from(fixture).toString('hex')); }); - it('encoding = null', function() { - return spawn('cat', [fixturePath], {encoding: null}).then(function(content) { - content.should.eql(Buffer.from(fixture)); - }); + it('encoding = null', () => { + return spawn(catCommand, [fixturePath], {encoding: null}).should.become(Buffer.from(fixture)); }); - it('stdio = inherit', function() { - return spawn('echo', ['something'], { - stdio: 'inherit' - }); - }); + it('stdio = inherit', () => spawn('echo', ['something'], { stdio: 'inherit' })); }); diff --git a/test/scripts/truncate.js b/test/scripts/truncate.js index cc29b062..67a1cb2d 100644 --- a/test/scripts/truncate.js +++ b/test/scripts/truncate.js @@ -1,40 +1,36 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line +require('chai').should(); -describe('truncate', function() { - var truncate = require('../../lib/truncate'); +describe('truncate', () => { + const truncate = require('../../lib/truncate'); - it('default', function() { + it('default', () => { truncate('Once upon a time in a world far far away') .should.eql('Once upon a time in a world...'); }); - it('shorter string', function() { + it('shorter string', () => { truncate('Once upon') .should.eql('Once upon'); }); - it('truncate', function() { + it('truncate', () => { truncate('Once upon a time in a world far far away', {length: 17}) .should.eql('Once upon a ti...'); }); - it('separator', function() { + it('separator', () => { truncate('Once upon a time in a world far far away', {length: 17, separator: ' '}) .should.eql('Once upon a...'); }); - it('omission', function() { + it('omission', () => { truncate('And they found that many people were sleeping better.', {length: 25, omission: '... (continued)'}) .should.eql('And they f... (continued)'); }); - it('str must be a string', function() { - try { - truncate(); - } catch (err) { - err.should.have.property('message', 'str must be a string!'); - } + it('str must be a string', () => { + truncate.should.throw('str must be a string!'); }); }); diff --git a/test/scripts/word_wrap.js b/test/scripts/word_wrap.js index ec89aed3..0da8242f 100644 --- a/test/scripts/word_wrap.js +++ b/test/scripts/word_wrap.js @@ -1,32 +1,28 @@ 'use strict'; -var should = require('chai').should(); // eslint-disable-line +require('chai').should(); -describe('wordWrap', function() { - var wordWrap = require('../../lib/word_wrap'); +describe('wordWrap', () => { + const wordWrap = require('../../lib/word_wrap'); - it('default', function() { + it('default', () => { wordWrap('Once upon a time').should.eql('Once upon a time'); }); - it('default width', function() { + it('default width', () => { wordWrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...') .should.eql('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\na successor to the throne turned out to be more trouble than anyone could have\nimagined...'); }); - it('width = 8', function() { + it('width = 8', () => { wordWrap('Once upon a time', {width: 8}).should.eql('Once\nupon a\ntime'); }); - it('width = 1', function() { + it('width = 1', () => { wordWrap('Once upon a time', {width: 1}).should.eql('Once\nupon\na\ntime'); }); - it('str must be a string', function() { - try { - wordWrap(); - } catch (err) { - err.should.have.property('message', 'str must be a string!'); - } + it('str must be a string', () => { + wordWrap.should.throw('str must be a string!'); }); });