diff --git a/.gitignore b/.gitignore index 5de9231..92463b6 100755 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,6 @@ ts-dist .nyc_output coverage .dev-doc -example \ No newline at end of file +example +doc/.vuepress/dist +publish.sh \ No newline at end of file diff --git a/dist/mock.browser.esm.js b/dist/mock.browser.esm.js index 0fa3492..e9a2e9b 100644 --- a/dist/mock.browser.esm.js +++ b/dist/mock.browser.esm.js @@ -1,5 +1,5 @@ /*! - * better-mock v0.0.2 + * better-mock v0.0.3 * (c) 2019-2019 lavyun@163.com * Released under the MIT License. */ function _typeof(obj) { @@ -40,7 +40,21 @@ var constant = { RE_PLACEHOLDER: /\\*@([^@#%&()\?\s]+)(?:\((.*?)\))?/g }; -var objectAssign = function objectAssign(target, varArgs) { +var __spreadArrays = undefined && undefined.__spreadArrays || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) { + s += arguments[i].length; + } + + for (var r = Array(s), k = 0, i = 0; i < il; i++) { + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) { + r[k] = a[j]; + } + } + + return r; +}; + +var objectAssign = function objectAssign(target, args) { // TypeError if undefined or null if (target == null) { throw new TypeError('Cannot convert undefined or null to object'); @@ -48,8 +62,8 @@ var objectAssign = function objectAssign(target, varArgs) { var to = Object(target); - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; + for (var i = 1; i < arguments.length; i++) { + var nextSource = arguments[i]; if (nextSource != null) { // Skip over if undefined or null @@ -81,8 +95,8 @@ var each = function each(obj, iterator, context) { } } }; -var type = function type(obj) { - return isDef(obj) ? Object.prototype.toString.call(obj).match(/\[object (\w+)\]/)[1].toLowerCase() : String(obj); +var type = function type(value) { + return isDef(value) ? Object.prototype.toString.call(value).match(/\[object (\w+)\]/)[1].toLowerCase() : String(value); }; var isDef = function isDef(value) { return value !== undefined && value !== null; @@ -131,19 +145,9 @@ var values = function values(obj) { return values; }; /** - * ### Mock.heredoc(fn) - * + * Mock.heredoc(fn) * 以直观、安全的方式书写(多行)HTML 模板。 - * - * 使用示例如下所示: - * - * const tpl = Mock.heredoc(function () { - * - * }) - * - * 相关阅读: - * - * [Creating multiline strings in JavaScript](http://stackoverflow.com/questions/805107/creating-multiline-strings-in-javascript) + * http://stackoverflow.com/questions/805107/creating-multiline-strings-in-javascript */ var heredoc = function heredoc(fn) { @@ -153,6 +157,15 @@ var heredoc = function heredoc(fn) { return fn.toString().replace(/^[^\/]+\/\*!?/, '').replace(/\*\/[^\/]+$/, '').replace(/^[\s\xA0]+/, '').replace(/[\s\xA0]+$/, ''); // .trim() }; var noop = function noop() {}; +var logInfo = function logInfo() { + var args = []; + + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + + console.log.apply(console, __spreadArrays(['[better-mock]'], args)); +}; var Util = /*#__PURE__*/Object.freeze({ objectAssign: objectAssign, @@ -169,7 +182,8 @@ var Util = /*#__PURE__*/Object.freeze({ keys: keys, values: values, heredoc: heredoc, - noop: noop + noop: noop, + logInfo: logInfo }); var MAX_NATURE_NUMBER = 9007199254740992; @@ -598,165 +612,16 @@ var helper = /*#__PURE__*/Object.freeze({ // image -var _adSize = ['300x250', '250x250', '240x400', '336x280', '180x150', '720x300', '468x60', '234x60', '88x31', '120x90', '120x60', '120x240', '125x125', '728x90', '160x600', '120x600', '300x600']; // BrandColors -// http://brandcolors.net/ -// 大牌公司的颜色集合 - -var _brandColors = { - '4ormat': '#fb0a2a', - '500px': '#02adea', - 'About.me (blue)': '#00405d', - 'About.me (yellow)': '#ffcc33', - 'Addvocate': '#ff6138', - 'Adobe': '#ff0000', - 'Aim': '#fcd20b', - 'Amazon': '#e47911', - 'Android': '#a4c639', - 'Angie\'s List': '#7fbb00', - 'AOL': '#0060a3', - 'Atlassian': '#003366', - 'Behance': '#053eff', - 'Big Cartel': '#97b538', - 'bitly': '#ee6123', - 'Blogger': '#fc4f08', - 'Boeing': '#0039a6', - 'Booking.com': '#003580', - 'Carbonmade': '#613854', - 'Cheddar': '#ff7243', - 'Code School': '#3d4944', - 'Delicious': '#205cc0', - 'Dell': '#3287c1', - 'Designmoo': '#e54a4f', - 'Deviantart': '#4e6252', - 'Designer News': '#2d72da', - 'Devour': '#fd0001', - 'DEWALT': '#febd17', - 'Disqus (blue)': '#59a3fc', - 'Disqus (orange)': '#db7132', - 'Dribbble': '#ea4c89', - 'Dropbox': '#3d9ae8', - 'Drupal': '#0c76ab', - 'Dunked': '#2a323a', - 'eBay': '#89c507', - 'Ember': '#f05e1b', - 'Engadget': '#00bdf6', - 'Envato': '#528036', - 'Etsy': '#eb6d20', - 'Evernote': '#5ba525', - 'Fab.com': '#dd0017', - 'Facebook': '#3b5998', - 'Firefox': '#e66000', - 'Flickr (blue)': '#0063dc', - 'Flickr (pink)': '#ff0084', - 'Forrst': '#5b9a68', - 'Foursquare': '#25a0ca', - 'Garmin': '#007cc3', - 'GetGlue': '#2d75a2', - 'Gimmebar': '#f70078', - 'GitHub': '#171515', - 'Google Blue': '#0140ca', - 'Google Green': '#16a61e', - 'Google Red': '#dd1812', - 'Google Yellow': '#fcca03', - 'Google+': '#dd4b39', - 'Grooveshark': '#f77f00', - 'Groupon': '#82b548', - 'Hacker News': '#ff6600', - 'HelloWallet': '#0085ca', - 'Heroku (light)': '#c7c5e6', - 'Heroku (dark)': '#6567a5', - 'HootSuite': '#003366', - 'Houzz': '#73ba37', - 'HTML5': '#ec6231', - 'IKEA': '#ffcc33', - 'IMDb': '#f3ce13', - 'Instagram': '#3f729b', - 'Intel': '#0071c5', - 'Intuit': '#365ebf', - 'Kickstarter': '#76cc1e', - 'kippt': '#e03500', - 'Kodery': '#00af81', - 'LastFM': '#c3000d', - 'LinkedIn': '#0e76a8', - 'Livestream': '#cf0005', - 'Lumo': '#576396', - 'Mixpanel': '#a086d3', - 'Meetup': '#e51937', - 'Nokia': '#183693', - 'NVIDIA': '#76b900', - 'Opera': '#cc0f16', - 'Path': '#e41f11', - 'PayPal (dark)': '#1e477a', - 'PayPal (light)': '#3b7bbf', - 'Pinboard': '#0000e6', - 'Pinterest': '#c8232c', - 'PlayStation': '#665cbe', - 'Pocket': '#ee4056', - 'Prezi': '#318bff', - 'Pusha': '#0f71b4', - 'Quora': '#a82400', - 'QUOTE.fm': '#66ceff', - 'Rdio': '#008fd5', - 'Readability': '#9c0000', - 'Red Hat': '#cc0000', - 'Resource': '#7eb400', - 'Rockpack': '#0ba6ab', - 'Roon': '#62b0d9', - 'RSS': '#ee802f', - 'Salesforce': '#1798c1', - 'Samsung': '#0c4da2', - 'Shopify': '#96bf48', - 'Skype': '#00aff0', - 'Snagajob': '#f47a20', - 'Softonic': '#008ace', - 'SoundCloud': '#ff7700', - 'Space Box': '#f86960', - 'Spotify': '#81b71a', - 'Sprint': '#fee100', - 'Squarespace': '#121212', - 'StackOverflow': '#ef8236', - 'Staples': '#cc0000', - 'Status Chart': '#d7584f', - 'Stripe': '#008cdd', - 'StudyBlue': '#00afe1', - 'StumbleUpon': '#f74425', - 'T-Mobile': '#ea0a8e', - 'Technorati': '#40a800', - 'The Next Web': '#ef4423', - 'Treehouse': '#5cb868', - 'Trulia': '#5eab1f', - 'Tumblr': '#34526f', - 'Twitch.tv': '#6441a5', - 'Twitter': '#00acee', - 'TYPO3': '#ff8700', - 'Ubuntu': '#dd4814', - 'Ustream': '#3388ff', - 'Verizon': '#ef1d1d', - 'Vimeo': '#86c9ef', - 'Vine': '#00a478', - 'Virb': '#06afd8', - 'Virgin Media': '#cc0000', - 'Wooga': '#5b009c', - 'WordPress (blue)': '#21759b', - 'WordPress (orange)': '#d54e21', - 'WordPress (grey)': '#464646', - 'Wunderlist': '#2b88d9', - 'XBOX': '#9bc848', - 'XING': '#126567', - 'Yahoo!': '#720e9e', - 'Yandex': '#ffcc00', - 'Yelp': '#c41200', - 'YouTube': '#c4302b', - 'Zalongo': '#5498dc', - 'Zendesk': '#78a300', - 'Zerply': '#9dcc7a', - 'Zootool': '#5e8b1d' -}; // 生成一个随机的图片地址。 -// 替代图片源 -// http://fpoimg.com/ -// 参考自 -// http://rensanning.iteye.com/blog/1933310 -// http://code.tutsplus.com/articles/the-top-8-placeholders-for-web-designers--net-19485 +var _adSize = ['300x250', '250x250', '240x400', '336x280', '180x150', '720x300', '468x60', '234x60', '88x31', '120x90', '120x60', '120x240', '125x125', '728x90', '160x600', '120x600', '300x600']; +/** + * 随机生成一个图片,使用:https://dummyimage.com/,例如: + * https://dummyimage.com/600x400/cc00cc/470047.png&text=hello + * @param size 图片大小 + * @param background 背景色 + * @param foreground 文字颜色 + * @param format 图片格式 + * @param text 文字 + */ var image = function image(size, background, foreground, format, text) { // Random.image( size, background, foreground, text ) @@ -769,66 +634,81 @@ var image = function image(size, background, foreground, format, text) { if (arguments.length === 3) { text = foreground; foreground = undefined; + } // Random.image( size, text ) + + + if (arguments.length === 2) { + text = background; + background = undefined; } // Random.image() - if (!size) size = pick(_adSize); - if (background && ~background.indexOf('#')) background = background.slice(1); - if (foreground && ~foreground.indexOf('#')) foreground = foreground.slice(1); // http://dummyimage.com/600x400/cc00cc/470047.png&text=hello + size = size || pick(_adSize); - return 'http://dummyimage.com/' + size + (background ? '/' + background : '') + (foreground ? '/' + foreground : '') + (format ? '.' + format : '') + (text ? '&text=' + text : ''); + if (background && ~background.indexOf('#')) { + background = background.slice(1); + } + + if (foreground && ~foreground.indexOf('#')) { + foreground = foreground.slice(1); + } + + return 'https://dummyimage.com/' + size + (background ? '/' + background : '') + (foreground ? '/' + foreground : '') + (format ? '.' + format : '') + (text ? '&text=' + text : ''); }; -var img = image; // 生成一段随机的 Base64 图片编码。 -// https://github.com/imsky/holder +var img = image; +/** + * 生成一个随机的base64图片 + * @param size 图片宽高 + * @param text 图片上的文字 + */ var dataImage = function dataImage(size, text) { - var canvas; + size = size || pick(_adSize); + text = text || size; + var background = pick(['#171515', '#e47911', '#183693', '#720e9e', '#c4302b', '#dd4814', '#00acee', '#0071c5', '#3d9ae8', '#ec6231', '#003580', '#e51937']); + var foreground = '#FFFFFF'; // browser if (typeof document !== 'undefined') { - canvas = document.createElement('canvas'); - } else { - // https://github.com/Automattic/node-canvas - // npm install canvas --save - // 安装问题: - // * http://stackoverflow.com/questions/22953206/gulp-issues-with-cario-install-command-not-found-when-trying-to-installing-canva - // * https://github.com/Automattic/node-canvas/issues/415 - // * https://github.com/Automattic/node-canvas/wiki/_pages - // PS:node-canvas 的安装过程实在是太繁琐了,所以不放入 package.json 的 dependencies。 - var Canvas = module.require('canvas'); - - canvas = new Canvas(); - } + var canvas = document.createElement('canvas'); + var ctx = canvas && canvas.getContext && canvas.getContext('2d'); - var ctx = canvas && canvas.getContext && canvas.getContext('2d'); + if (!canvas || !ctx) { + return ''; + } - if (!canvas || !ctx) { - return ''; - } + var sizeArr = size.split('x'); + var width = parseInt(sizeArr[0], 10); + var height = parseInt(sizeArr[1], 10); + canvas.width = width; + canvas.height = height; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = background; + ctx.fillRect(0, 0, width, height); + ctx.fillStyle = foreground; + ctx.font = 'bold 14px sans-serif'; + ctx.fillText(text, width / 2, height / 2, width); + return canvas.toDataURL('image/png'); + } else { + try { + var request = require('sync-request'); - if (!size) { - size = pick(_adSize); - } + var res = request('GET', image(size, background, foreground, text), { + cache: 'memory', + timeout: 8000 + }); + var buffer = res.getBody(); + return 'data:image/png;base64,' + buffer.toString('base64'); + } catch (err) { + if (err.toString().includes('timed out')) { + logInfo('generate image timeout'); + } else { + logInfo(err); + } - text = text !== undefined ? text : size; - size = size.split('x'); - var width = parseInt(size[0], 10); - var height = parseInt(size[1], 10); - - var background = _brandColors[pick(keys(_brandColors))]; - - var foreground = '#FFF'; - var text_height = 14; - var font = 'sans-serif'; - canvas.width = width; - canvas.height = height; - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = background; - ctx.fillRect(0, 0, width, height); - ctx.fillStyle = foreground; - ctx.font = 'bold ' + text_height + 'px ' + font; - ctx.fillText(text, width / 2, height / 2, width); - return canvas.toDataURL('image/png'); + return ''; + } + } }; var image$1 = /*#__PURE__*/Object.freeze({ @@ -1180,7 +1060,7 @@ var text = /*#__PURE__*/Object.freeze({ ctitle: ctitle }); -var __spreadArrays = undefined && undefined.__spreadArrays || function () { +var __spreadArrays$1 = undefined && undefined.__spreadArrays || function () { for (var s = 0, i = 0, il = arguments.length; i < il; i++) { s += arguments[i].length; } @@ -1197,7 +1077,7 @@ var __spreadArrays = undefined && undefined.__spreadArrays || function () { var first = function first() { var male = ["James", "John", "Robert", "Michael", "William", "David", "Richard", "Charles", "Joseph", "Thomas", "Christopher", "Daniel", "Paul", "Mark", "Donald", "George", "Kenneth", "Steven", "Edward", "Brian", "Ronald", "Anthony", "Kevin", "Jason", "Matthew", "Gary", "Timothy", "Jose", "Larry", "Jeffrey", "Frank", "Scott", "Eric"]; var female = ["Mary", "Patricia", "Linda", "Barbara", "Elizabeth", "Jennifer", "Maria", "Susan", "Margaret", "Dorothy", "Lisa", "Nancy", "Karen", "Betty", "Helen", "Sandra", "Donna", "Carol", "Ruth", "Sharon", "Michelle", "Laura", "Sarah", "Kimberly", "Deborah", "Jessica", "Shirley", "Cynthia", "Angela", "Melissa", "Brenda", "Amy", "Anna"]; - return pick(__spreadArrays(male, female)); + return pick(__spreadArrays$1(male, female)); }; // 随机生成一个常见的英文姓。 var last = function last() { @@ -6722,7 +6602,11 @@ var key = 0; var increment = function increment(step) { return key += Number(step) || 1; // step? }; -var inc = increment; // 生成一个版本号 +var inc = increment; +/** + * 随机生成一个版本号 + * @param depth 版本号的层级,默认为3 + */ var version = function version(depth) { if (depth === void 0) { @@ -6736,6 +6620,14 @@ var version = function version(depth) { } return numbers.join('.'); +}; // 随机生成一个中国手机号 + +var phone = function phone() { + var segments = [// 移动号段 + '134', '135', '136', '137', '138', '139', '147', '150', '151', '152', '157', '158', '159', '165', '172', '178', '182', '183', '184', '187', '188', // 联通号段 + '130', '131', '132', '145', '155', '156', '171', '175', '176', '185', '186', // 电信号段 + '133', '149', '153', '173', '174', '177', '180', '181', '189', '191']; + return pick(segments) + string('number', 8); }; var misc = /*#__PURE__*/Object.freeze({ @@ -6744,7 +6636,8 @@ var misc = /*#__PURE__*/Object.freeze({ id: id, increment: increment, inc: inc, - version: version + version: version, + phone: phone }); var __assign = undefined && undefined.__assign || function () { @@ -9195,21 +9088,47 @@ function find(options) { for (var sUrlType in MockXMLHttpRequest.Mock.mocked) { var item = MockXMLHttpRequest.Mock.mocked[sUrlType]; - if ((!item.rurl || match(item.rurl, options.url)) && (!item.rtype || match(item.rtype, options.type.toLowerCase()))) { - // console.log('[mock]', options.url, '>', item.rurl) + if ((!item.rurl || matchUrl(item.rurl, options.url)) && (!item.rtype || matchType(item.rtype, options.type))) { return item; } } - function match(expected, actual) { - if (type(expected) === 'string') { - return expected === actual; + function matchUrl(expected, actual) { + if (isString(expected)) { + if (expected === actual) { + return true; + } // expected: /hello/world + // actual: /hello/world?type=1 + + + if (actual.indexOf(expected) === 0 && actual[expected.length] === '?') { + return true; + } } - if (type(expected) === 'regexp') { + if (isRegExp(expected)) { return expected.test(actual); } + + return false; } + + function matchType(expected, actual) { + if (isString(expected) || isRegExp(expected)) { + return new RegExp(expected, 'i').test(actual); + } + + return false; + } // function match(expected: string | RegExp, actual: string): boolean { + // if (util.isString(expected)) { + // return expected === actual + // } + // if (util.isRegExp(expected)) { + // return new RegExp(expected, 'i').test(actual) + // } + // return false + // } + } // 数据模板 => 响应数据 @@ -9232,7 +9151,7 @@ var Mock = { return MockXMLHttpRequest.setup(settings); }, mocked: {}, - version: '0.0.2' + version: '0.0.3' }; // 避免循环依赖 if (MockXMLHttpRequest) { diff --git a/dist/mock.browser.js b/dist/mock.browser.js index f393886..0773f35 100644 --- a/dist/mock.browser.js +++ b/dist/mock.browser.js @@ -1,5 +1,5 @@ /*! - * better-mock v0.0.2 + * better-mock v0.0.3 * (c) 2019-2019 lavyun@163.com * Released under the MIT License. */ (function (global, factory) { @@ -46,7 +46,21 @@ RE_PLACEHOLDER: /\\*@([^@#%&()\?\s]+)(?:\((.*?)\))?/g }; - var objectAssign = function objectAssign(target, varArgs) { + var __spreadArrays = undefined && undefined.__spreadArrays || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) { + s += arguments[i].length; + } + + for (var r = Array(s), k = 0, i = 0; i < il; i++) { + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) { + r[k] = a[j]; + } + } + + return r; + }; + + var objectAssign = function objectAssign(target, args) { // TypeError if undefined or null if (target == null) { throw new TypeError('Cannot convert undefined or null to object'); @@ -54,8 +68,8 @@ var to = Object(target); - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; + for (var i = 1; i < arguments.length; i++) { + var nextSource = arguments[i]; if (nextSource != null) { // Skip over if undefined or null @@ -87,8 +101,8 @@ } } }; - var type = function type(obj) { - return isDef(obj) ? Object.prototype.toString.call(obj).match(/\[object (\w+)\]/)[1].toLowerCase() : String(obj); + var type = function type(value) { + return isDef(value) ? Object.prototype.toString.call(value).match(/\[object (\w+)\]/)[1].toLowerCase() : String(value); }; var isDef = function isDef(value) { return value !== undefined && value !== null; @@ -137,19 +151,9 @@ return values; }; /** - * ### Mock.heredoc(fn) - * + * Mock.heredoc(fn) * 以直观、安全的方式书写(多行)HTML 模板。 - * - * 使用示例如下所示: - * - * const tpl = Mock.heredoc(function () { - * - * }) - * - * 相关阅读: - * - * [Creating multiline strings in JavaScript](http://stackoverflow.com/questions/805107/creating-multiline-strings-in-javascript) + * http://stackoverflow.com/questions/805107/creating-multiline-strings-in-javascript */ var heredoc = function heredoc(fn) { @@ -159,6 +163,15 @@ return fn.toString().replace(/^[^\/]+\/\*!?/, '').replace(/\*\/[^\/]+$/, '').replace(/^[\s\xA0]+/, '').replace(/[\s\xA0]+$/, ''); // .trim() }; var noop = function noop() {}; + var logInfo = function logInfo() { + var args = []; + + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + + console.log.apply(console, __spreadArrays(['[better-mock]'], args)); + }; var Util = /*#__PURE__*/Object.freeze({ objectAssign: objectAssign, @@ -175,7 +188,8 @@ keys: keys, values: values, heredoc: heredoc, - noop: noop + noop: noop, + logInfo: logInfo }); var MAX_NATURE_NUMBER = 9007199254740992; @@ -604,165 +618,16 @@ // image - var _adSize = ['300x250', '250x250', '240x400', '336x280', '180x150', '720x300', '468x60', '234x60', '88x31', '120x90', '120x60', '120x240', '125x125', '728x90', '160x600', '120x600', '300x600']; // BrandColors - // http://brandcolors.net/ - // 大牌公司的颜色集合 - - var _brandColors = { - '4ormat': '#fb0a2a', - '500px': '#02adea', - 'About.me (blue)': '#00405d', - 'About.me (yellow)': '#ffcc33', - 'Addvocate': '#ff6138', - 'Adobe': '#ff0000', - 'Aim': '#fcd20b', - 'Amazon': '#e47911', - 'Android': '#a4c639', - 'Angie\'s List': '#7fbb00', - 'AOL': '#0060a3', - 'Atlassian': '#003366', - 'Behance': '#053eff', - 'Big Cartel': '#97b538', - 'bitly': '#ee6123', - 'Blogger': '#fc4f08', - 'Boeing': '#0039a6', - 'Booking.com': '#003580', - 'Carbonmade': '#613854', - 'Cheddar': '#ff7243', - 'Code School': '#3d4944', - 'Delicious': '#205cc0', - 'Dell': '#3287c1', - 'Designmoo': '#e54a4f', - 'Deviantart': '#4e6252', - 'Designer News': '#2d72da', - 'Devour': '#fd0001', - 'DEWALT': '#febd17', - 'Disqus (blue)': '#59a3fc', - 'Disqus (orange)': '#db7132', - 'Dribbble': '#ea4c89', - 'Dropbox': '#3d9ae8', - 'Drupal': '#0c76ab', - 'Dunked': '#2a323a', - 'eBay': '#89c507', - 'Ember': '#f05e1b', - 'Engadget': '#00bdf6', - 'Envato': '#528036', - 'Etsy': '#eb6d20', - 'Evernote': '#5ba525', - 'Fab.com': '#dd0017', - 'Facebook': '#3b5998', - 'Firefox': '#e66000', - 'Flickr (blue)': '#0063dc', - 'Flickr (pink)': '#ff0084', - 'Forrst': '#5b9a68', - 'Foursquare': '#25a0ca', - 'Garmin': '#007cc3', - 'GetGlue': '#2d75a2', - 'Gimmebar': '#f70078', - 'GitHub': '#171515', - 'Google Blue': '#0140ca', - 'Google Green': '#16a61e', - 'Google Red': '#dd1812', - 'Google Yellow': '#fcca03', - 'Google+': '#dd4b39', - 'Grooveshark': '#f77f00', - 'Groupon': '#82b548', - 'Hacker News': '#ff6600', - 'HelloWallet': '#0085ca', - 'Heroku (light)': '#c7c5e6', - 'Heroku (dark)': '#6567a5', - 'HootSuite': '#003366', - 'Houzz': '#73ba37', - 'HTML5': '#ec6231', - 'IKEA': '#ffcc33', - 'IMDb': '#f3ce13', - 'Instagram': '#3f729b', - 'Intel': '#0071c5', - 'Intuit': '#365ebf', - 'Kickstarter': '#76cc1e', - 'kippt': '#e03500', - 'Kodery': '#00af81', - 'LastFM': '#c3000d', - 'LinkedIn': '#0e76a8', - 'Livestream': '#cf0005', - 'Lumo': '#576396', - 'Mixpanel': '#a086d3', - 'Meetup': '#e51937', - 'Nokia': '#183693', - 'NVIDIA': '#76b900', - 'Opera': '#cc0f16', - 'Path': '#e41f11', - 'PayPal (dark)': '#1e477a', - 'PayPal (light)': '#3b7bbf', - 'Pinboard': '#0000e6', - 'Pinterest': '#c8232c', - 'PlayStation': '#665cbe', - 'Pocket': '#ee4056', - 'Prezi': '#318bff', - 'Pusha': '#0f71b4', - 'Quora': '#a82400', - 'QUOTE.fm': '#66ceff', - 'Rdio': '#008fd5', - 'Readability': '#9c0000', - 'Red Hat': '#cc0000', - 'Resource': '#7eb400', - 'Rockpack': '#0ba6ab', - 'Roon': '#62b0d9', - 'RSS': '#ee802f', - 'Salesforce': '#1798c1', - 'Samsung': '#0c4da2', - 'Shopify': '#96bf48', - 'Skype': '#00aff0', - 'Snagajob': '#f47a20', - 'Softonic': '#008ace', - 'SoundCloud': '#ff7700', - 'Space Box': '#f86960', - 'Spotify': '#81b71a', - 'Sprint': '#fee100', - 'Squarespace': '#121212', - 'StackOverflow': '#ef8236', - 'Staples': '#cc0000', - 'Status Chart': '#d7584f', - 'Stripe': '#008cdd', - 'StudyBlue': '#00afe1', - 'StumbleUpon': '#f74425', - 'T-Mobile': '#ea0a8e', - 'Technorati': '#40a800', - 'The Next Web': '#ef4423', - 'Treehouse': '#5cb868', - 'Trulia': '#5eab1f', - 'Tumblr': '#34526f', - 'Twitch.tv': '#6441a5', - 'Twitter': '#00acee', - 'TYPO3': '#ff8700', - 'Ubuntu': '#dd4814', - 'Ustream': '#3388ff', - 'Verizon': '#ef1d1d', - 'Vimeo': '#86c9ef', - 'Vine': '#00a478', - 'Virb': '#06afd8', - 'Virgin Media': '#cc0000', - 'Wooga': '#5b009c', - 'WordPress (blue)': '#21759b', - 'WordPress (orange)': '#d54e21', - 'WordPress (grey)': '#464646', - 'Wunderlist': '#2b88d9', - 'XBOX': '#9bc848', - 'XING': '#126567', - 'Yahoo!': '#720e9e', - 'Yandex': '#ffcc00', - 'Yelp': '#c41200', - 'YouTube': '#c4302b', - 'Zalongo': '#5498dc', - 'Zendesk': '#78a300', - 'Zerply': '#9dcc7a', - 'Zootool': '#5e8b1d' - }; // 生成一个随机的图片地址。 - // 替代图片源 - // http://fpoimg.com/ - // 参考自 - // http://rensanning.iteye.com/blog/1933310 - // http://code.tutsplus.com/articles/the-top-8-placeholders-for-web-designers--net-19485 + var _adSize = ['300x250', '250x250', '240x400', '336x280', '180x150', '720x300', '468x60', '234x60', '88x31', '120x90', '120x60', '120x240', '125x125', '728x90', '160x600', '120x600', '300x600']; + /** + * 随机生成一个图片,使用:https://dummyimage.com/,例如: + * https://dummyimage.com/600x400/cc00cc/470047.png&text=hello + * @param size 图片大小 + * @param background 背景色 + * @param foreground 文字颜色 + * @param format 图片格式 + * @param text 文字 + */ var image = function image(size, background, foreground, format, text) { // Random.image( size, background, foreground, text ) @@ -775,66 +640,81 @@ if (arguments.length === 3) { text = foreground; foreground = undefined; + } // Random.image( size, text ) + + + if (arguments.length === 2) { + text = background; + background = undefined; } // Random.image() - if (!size) size = pick(_adSize); - if (background && ~background.indexOf('#')) background = background.slice(1); - if (foreground && ~foreground.indexOf('#')) foreground = foreground.slice(1); // http://dummyimage.com/600x400/cc00cc/470047.png&text=hello + size = size || pick(_adSize); - return 'http://dummyimage.com/' + size + (background ? '/' + background : '') + (foreground ? '/' + foreground : '') + (format ? '.' + format : '') + (text ? '&text=' + text : ''); + if (background && ~background.indexOf('#')) { + background = background.slice(1); + } + + if (foreground && ~foreground.indexOf('#')) { + foreground = foreground.slice(1); + } + + return 'https://dummyimage.com/' + size + (background ? '/' + background : '') + (foreground ? '/' + foreground : '') + (format ? '.' + format : '') + (text ? '&text=' + text : ''); }; - var img = image; // 生成一段随机的 Base64 图片编码。 - // https://github.com/imsky/holder + var img = image; + /** + * 生成一个随机的base64图片 + * @param size 图片宽高 + * @param text 图片上的文字 + */ var dataImage = function dataImage(size, text) { - var canvas; + size = size || pick(_adSize); + text = text || size; + var background = pick(['#171515', '#e47911', '#183693', '#720e9e', '#c4302b', '#dd4814', '#00acee', '#0071c5', '#3d9ae8', '#ec6231', '#003580', '#e51937']); + var foreground = '#FFFFFF'; // browser if (typeof document !== 'undefined') { - canvas = document.createElement('canvas'); - } else { - // https://github.com/Automattic/node-canvas - // npm install canvas --save - // 安装问题: - // * http://stackoverflow.com/questions/22953206/gulp-issues-with-cario-install-command-not-found-when-trying-to-installing-canva - // * https://github.com/Automattic/node-canvas/issues/415 - // * https://github.com/Automattic/node-canvas/wiki/_pages - // PS:node-canvas 的安装过程实在是太繁琐了,所以不放入 package.json 的 dependencies。 - var Canvas = module.require('canvas'); - - canvas = new Canvas(); - } + var canvas = document.createElement('canvas'); + var ctx = canvas && canvas.getContext && canvas.getContext('2d'); - var ctx = canvas && canvas.getContext && canvas.getContext('2d'); + if (!canvas || !ctx) { + return ''; + } - if (!canvas || !ctx) { - return ''; - } + var sizeArr = size.split('x'); + var width = parseInt(sizeArr[0], 10); + var height = parseInt(sizeArr[1], 10); + canvas.width = width; + canvas.height = height; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = background; + ctx.fillRect(0, 0, width, height); + ctx.fillStyle = foreground; + ctx.font = 'bold 14px sans-serif'; + ctx.fillText(text, width / 2, height / 2, width); + return canvas.toDataURL('image/png'); + } else { + try { + var request = require('sync-request'); - if (!size) { - size = pick(_adSize); - } + var res = request('GET', image(size, background, foreground, text), { + cache: 'memory', + timeout: 8000 + }); + var buffer = res.getBody(); + return 'data:image/png;base64,' + buffer.toString('base64'); + } catch (err) { + if (err.toString().includes('timed out')) { + logInfo('generate image timeout'); + } else { + logInfo(err); + } - text = text !== undefined ? text : size; - size = size.split('x'); - var width = parseInt(size[0], 10); - var height = parseInt(size[1], 10); - - var background = _brandColors[pick(keys(_brandColors))]; - - var foreground = '#FFF'; - var text_height = 14; - var font = 'sans-serif'; - canvas.width = width; - canvas.height = height; - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = background; - ctx.fillRect(0, 0, width, height); - ctx.fillStyle = foreground; - ctx.font = 'bold ' + text_height + 'px ' + font; - ctx.fillText(text, width / 2, height / 2, width); - return canvas.toDataURL('image/png'); + return ''; + } + } }; var image$1 = /*#__PURE__*/Object.freeze({ @@ -1186,7 +1066,7 @@ ctitle: ctitle }); - var __spreadArrays = undefined && undefined.__spreadArrays || function () { + var __spreadArrays$1 = undefined && undefined.__spreadArrays || function () { for (var s = 0, i = 0, il = arguments.length; i < il; i++) { s += arguments[i].length; } @@ -1203,7 +1083,7 @@ var first = function first() { var male = ["James", "John", "Robert", "Michael", "William", "David", "Richard", "Charles", "Joseph", "Thomas", "Christopher", "Daniel", "Paul", "Mark", "Donald", "George", "Kenneth", "Steven", "Edward", "Brian", "Ronald", "Anthony", "Kevin", "Jason", "Matthew", "Gary", "Timothy", "Jose", "Larry", "Jeffrey", "Frank", "Scott", "Eric"]; var female = ["Mary", "Patricia", "Linda", "Barbara", "Elizabeth", "Jennifer", "Maria", "Susan", "Margaret", "Dorothy", "Lisa", "Nancy", "Karen", "Betty", "Helen", "Sandra", "Donna", "Carol", "Ruth", "Sharon", "Michelle", "Laura", "Sarah", "Kimberly", "Deborah", "Jessica", "Shirley", "Cynthia", "Angela", "Melissa", "Brenda", "Amy", "Anna"]; - return pick(__spreadArrays(male, female)); + return pick(__spreadArrays$1(male, female)); }; // 随机生成一个常见的英文姓。 var last = function last() { @@ -6728,7 +6608,11 @@ var increment = function increment(step) { return key += Number(step) || 1; // step? }; - var inc = increment; // 生成一个版本号 + var inc = increment; + /** + * 随机生成一个版本号 + * @param depth 版本号的层级,默认为3 + */ var version = function version(depth) { if (depth === void 0) { @@ -6742,6 +6626,14 @@ } return numbers.join('.'); + }; // 随机生成一个中国手机号 + + var phone = function phone() { + var segments = [// 移动号段 + '134', '135', '136', '137', '138', '139', '147', '150', '151', '152', '157', '158', '159', '165', '172', '178', '182', '183', '184', '187', '188', // 联通号段 + '130', '131', '132', '145', '155', '156', '171', '175', '176', '185', '186', // 电信号段 + '133', '149', '153', '173', '174', '177', '180', '181', '189', '191']; + return pick(segments) + string('number', 8); }; var misc = /*#__PURE__*/Object.freeze({ @@ -6750,7 +6642,8 @@ id: id, increment: increment, inc: inc, - version: version + version: version, + phone: phone }); var __assign = undefined && undefined.__assign || function () { @@ -9201,21 +9094,47 @@ for (var sUrlType in MockXMLHttpRequest.Mock.mocked) { var item = MockXMLHttpRequest.Mock.mocked[sUrlType]; - if ((!item.rurl || match(item.rurl, options.url)) && (!item.rtype || match(item.rtype, options.type.toLowerCase()))) { - // console.log('[mock]', options.url, '>', item.rurl) + if ((!item.rurl || matchUrl(item.rurl, options.url)) && (!item.rtype || matchType(item.rtype, options.type))) { return item; } } - function match(expected, actual) { - if (type(expected) === 'string') { - return expected === actual; + function matchUrl(expected, actual) { + if (isString(expected)) { + if (expected === actual) { + return true; + } // expected: /hello/world + // actual: /hello/world?type=1 + + + if (actual.indexOf(expected) === 0 && actual[expected.length] === '?') { + return true; + } } - if (type(expected) === 'regexp') { + if (isRegExp(expected)) { return expected.test(actual); } + + return false; } + + function matchType(expected, actual) { + if (isString(expected) || isRegExp(expected)) { + return new RegExp(expected, 'i').test(actual); + } + + return false; + } // function match(expected: string | RegExp, actual: string): boolean { + // if (util.isString(expected)) { + // return expected === actual + // } + // if (util.isRegExp(expected)) { + // return new RegExp(expected, 'i').test(actual) + // } + // return false + // } + } // 数据模板 => 响应数据 @@ -9238,7 +9157,7 @@ return MockXMLHttpRequest.setup(settings); }, mocked: {}, - version: '0.0.2' + version: '0.0.3' }; // 避免循环依赖 if (MockXMLHttpRequest) { diff --git a/dist/mock.browser.min.js b/dist/mock.browser.min.js index cabbc60..00fba1f 100644 --- a/dist/mock.browser.min.js +++ b/dist/mock.browser.min.js @@ -1,5 +1,5 @@ /*! - * better-mock v0.0.2 + * better-mock v0.0.3 * (c) 2019-2019 lavyun@163.com * Released under the MIT License. */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).Mock=t()}(this,function(){"use strict";function _typeof(e){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var constant={GUID:1,RE_KEY:/(.+)\|(?:\+(\d+)|([\+\-]?\d+-?[\+\-]?\d*)?(?:\.(\d+-?\d*))?)/,RE_RANGE:/([\+\-]?\d+)-?([\+\-]?\d+)?/,RE_PLACEHOLDER:/\\*@([^@#%&()\?\s]+)(?:\((.*?)\))?/g},objectAssign=function(e,t){if(null==e)throw new TypeError("Cannot convert undefined or null to object");for(var n=Object(e),r=1;r1/(e+t)*e?!n:n):.5<=Math.random()},bool=_boolean,natural=function(e,t){return void 0===e&&(e=0),void 0===t&&(t=MAX_NATURE_NUMBER),e=parseInt(e.toString(),10),t=parseInt(t.toString(),10),Math.round(Math.random()*(t-e))+e},integer=function(e,t){return void 0===e&&(e=MIN_NATURE_NUMBER),void 0===t&&(t=MAX_NATURE_NUMBER),e=parseInt(e.toString(),10),t=parseInt(t.toString(),10),Math.round(Math.random()*(t-e))+e},_int=integer,_float=function(e,t,n,r){n=isDef(n)?n:0,n=Math.max(Math.min(n,17),0),r=isDef(r)?r:17,r=Math.max(Math.min(r,17),0);for(var a=integer(e,t)+".",i=0,o=natural(n,r);ion?(n=o.charAt(on),on++):(n=null,0===mn&&c(qt)),null!==n?(cn=e,null===(t=jt(n))&&(on=e),t):(on=e,O)):(on=e,O)}function x(){var e,t,n,r;if(e=on,o.substr(on,2)===$t?(t=$t,on+=2):(t=null,0===mn&&c(Gt)),null!==t){if(n=[],Wt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Vt)),null!==r)for(;null!==r;)n.push(r),Wt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Vt));else n=O;e=null!==n?(cn=e,null===(t=Jt(n))&&(on=e),t):(on=e,O)}else on=e,e=O;return e}function A(){var e,t,n,r;if(e=on,o.substr(on,2)===Kt?(t=Kt,on+=2):(t=null,0===mn&&c(Qt)),null!==t){if(n=[],Yt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Zt)),null!==r)for(;null!==r;)n.push(r),Yt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Zt));else n=O;e=null!==n?(cn=e,null===(t=en(n))&&(on=e),t):(on=e,O)}else on=e,e=O;return e}function k(){var e,t,n,r;if(e=on,o.substr(on,2)===tn?(t=tn,on+=2):(t=null,0===mn&&c(nn)),null!==t){if(n=[],Yt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Zt)),null!==r)for(;null!==r;)n.push(r),Yt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Zt));else n=O;e=null!==n?(cn=e,null===(t=rn(n))&&(on=e),t):(on=e,O)}else on=e,e=O;return e}function S(){var e,t;return e=on,o.substr(on,2)===$t?(t=$t,on+=2):(t=null,0===mn&&c(Gt)),null!==t&&(cn=e,t=an()),null===t&&(on=e),e=t}function T(){var e,t,n;return e=on,92===o.charCodeAt(on)?(t=Ft,on++):(t=null,0===mn&&c(Ut)),e=null!==t?(o.length>on?(n=o.charAt(on),on++):(n=null,0===mn&&c(qt)),null!==n?(cn=e,null===(t=ze(n))&&(on=e),t):(on=e,O)):(on=e,O)}var C,_=11/(e+t)*e?!n:n):.5<=Math.random()},bool=_boolean,natural=function(e,t){return void 0===e&&(e=0),void 0===t&&(t=MAX_NATURE_NUMBER),e=parseInt(e.toString(),10),t=parseInt(t.toString(),10),Math.round(Math.random()*(t-e))+e},integer=function(e,t){return void 0===e&&(e=MIN_NATURE_NUMBER),void 0===t&&(t=MAX_NATURE_NUMBER),e=parseInt(e.toString(),10),t=parseInt(t.toString(),10),Math.round(Math.random()*(t-e))+e},_int=integer,_float=function(e,t,n,r){n=isDef(n)?n:0,n=Math.max(Math.min(n,17),0),r=isDef(r)?r:17,r=Math.max(Math.min(r,17),0);for(var a=integer(e,t)+".",i=0,o=natural(n,r);ion?(n=o.charAt(on),on++):(n=null,0===mn&&c(qt)),null!==n?(cn=e,null===(t=jt(n))&&(on=e),t):(on=e,O)):(on=e,O)}function b(){var e,t,n,r;if(e=on,o.substr(on,2)===zt?(t=zt,on+=2):(t=null,0===mn&&c(Gt)),null!==t){if(n=[],Jt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Qt)),null!==r)for(;null!==r;)n.push(r),Jt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Qt));else n=O;e=null!==n?(cn=e,null===(t=Wt(n))&&(on=e),t):(on=e,O)}else on=e,e=O;return e}function A(){var e,t,n,r;if(e=on,o.substr(on,2)===Kt?(t=Kt,on+=2):(t=null,0===mn&&c(Vt)),null!==t){if(n=[],Yt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Zt)),null!==r)for(;null!==r;)n.push(r),Yt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Zt));else n=O;e=null!==n?(cn=e,null===(t=en(n))&&(on=e),t):(on=e,O)}else on=e,e=O;return e}function C(){var e,t,n,r;if(e=on,o.substr(on,2)===tn?(t=tn,on+=2):(t=null,0===mn&&c(nn)),null!==t){if(n=[],Yt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Zt)),null!==r)for(;null!==r;)n.push(r),Yt.test(o.charAt(on))?(r=o.charAt(on),on++):(r=null,0===mn&&c(Zt));else n=O;e=null!==n?(cn=e,null===(t=rn(n))&&(on=e),t):(on=e,O)}else on=e,e=O;return e}function k(){var e,t;return e=on,o.substr(on,2)===zt?(t=zt,on+=2):(t=null,0===mn&&c(Gt)),null!==t&&(cn=e,t=an()),null===t&&(on=e),e=t}function _(){var e,t,n;return e=on,92===o.charCodeAt(on)?(t=Ft,on++):(t=null,0===mn&&c(Ut)),e=null!==t?(o.length>on?(n=o.charAt(on),on++):(n=null,0===mn&&c(qt)),null!==n?(cn=e,null===(t=Be(n))&&(on=e),t):(on=e,O)):(on=e,O)}var S,T=1 101 Random.increment(1000) // => 1101 -``` \ No newline at end of file +``` + +## Random.phone + +* Random.phone() + +生成一个中国的手机号。 + +```js +Random.phone() +// => 13088757656 +``` diff --git a/package.json b/package.json index a495f78..5308148 100755 --- a/package.json +++ b/package.json @@ -2,14 +2,14 @@ "name": "better-mock", "description": "Forked from Mockjs. Generate random data & Intercept ajax request", "author": "lavyun@163.com", - "version": "0.0.2", + "version": "0.0.3", "main": "./dist/mock.node.js", "module": "./dist/mock.browser.esm.js", "scripts": { "test": "mochify", "cover": "nyc --reporter=lcov --instrument false mochify --transform [ babelify --ignore [ test ] --plugins [ babel-plugin-istanbul ] ]", "coveralls": "cat ./coverage/lcov.info | coveralls", - "clear": "rimraf dist && rimraf typings", + "clear": "rimraf dist", "build": "npm run clear && tsc && node build/build.js && rimraf ts-dist", "doc:dev": "vuepress dev doc", "doc:build": "vuepress build doc", @@ -24,6 +24,24 @@ "intercept request", "ajax" ], + "files": [ + "bin", + "dist", + "src", + "test", + "LICENCE", + "package.json", + "README.md", + "tsconfig.json" + ], + "bin": { + "random": "bin/random" + }, + "types": "./typings/index.d.ts", + "dependencies": { + "china-location": "^2.0.0", + "sync-request": "^6.1.0" + }, "devDependencies": { "@babel/core": "^7.4.5", "@babel/preset-env": "^7.4.5", @@ -52,16 +70,10 @@ "type": "git", "url": "https://github.com/lavyun/better-mock" }, - "bin": { - "random": "bin/random" - }, "licenses": [ { "type": "MIT", "url": "https://github.com/lavyun/better-mock/blob/master/LICENSE" } - ], - "dependencies": { - "china-location": "^2.0.0" - } + ] } diff --git a/src/lib/random/image.ts b/src/lib/random/image.ts index c4f35c2..8a43b80 100755 --- a/src/lib/random/image.ts +++ b/src/lib/random/image.ts @@ -3,169 +3,22 @@ import * as helper from './helper' import * as utils from '../util' // 常见的广告宽高 -const _adSize: string[] = ['300x250', '250x250', '240x400', '336x280', '180x150', '720x300', '468x60', '234x60', '88x31', '120x90', '120x60', '120x240', '125x125', '728x90', '160x600', '120x600', '300x600'] +const _adSize: string[] = [ + '300x250', '250x250', '240x400', '336x280', '180x150', '720x300', + '468x60', '234x60', '88x31', '120x90', '120x60', '120x240', + '125x125', '728x90', '160x600', '120x600', '300x600' +] -// BrandColors -// http://brandcolors.net/ -// 大牌公司的颜色集合 -const _brandColors = { - '4ormat': '#fb0a2a', - '500px': '#02adea', - 'About.me (blue)': '#00405d', - 'About.me (yellow)': '#ffcc33', - 'Addvocate': '#ff6138', - 'Adobe': '#ff0000', - 'Aim': '#fcd20b', - 'Amazon': '#e47911', - 'Android': '#a4c639', - 'Angie\'s List': '#7fbb00', - 'AOL': '#0060a3', - 'Atlassian': '#003366', - 'Behance': '#053eff', - 'Big Cartel': '#97b538', - 'bitly': '#ee6123', - 'Blogger': '#fc4f08', - 'Boeing': '#0039a6', - 'Booking.com': '#003580', - 'Carbonmade': '#613854', - 'Cheddar': '#ff7243', - 'Code School': '#3d4944', - 'Delicious': '#205cc0', - 'Dell': '#3287c1', - 'Designmoo': '#e54a4f', - 'Deviantart': '#4e6252', - 'Designer News': '#2d72da', - 'Devour': '#fd0001', - 'DEWALT': '#febd17', - 'Disqus (blue)': '#59a3fc', - 'Disqus (orange)': '#db7132', - 'Dribbble': '#ea4c89', - 'Dropbox': '#3d9ae8', - 'Drupal': '#0c76ab', - 'Dunked': '#2a323a', - 'eBay': '#89c507', - 'Ember': '#f05e1b', - 'Engadget': '#00bdf6', - 'Envato': '#528036', - 'Etsy': '#eb6d20', - 'Evernote': '#5ba525', - 'Fab.com': '#dd0017', - 'Facebook': '#3b5998', - 'Firefox': '#e66000', - 'Flickr (blue)': '#0063dc', - 'Flickr (pink)': '#ff0084', - 'Forrst': '#5b9a68', - 'Foursquare': '#25a0ca', - 'Garmin': '#007cc3', - 'GetGlue': '#2d75a2', - 'Gimmebar': '#f70078', - 'GitHub': '#171515', - 'Google Blue': '#0140ca', - 'Google Green': '#16a61e', - 'Google Red': '#dd1812', - 'Google Yellow': '#fcca03', - 'Google+': '#dd4b39', - 'Grooveshark': '#f77f00', - 'Groupon': '#82b548', - 'Hacker News': '#ff6600', - 'HelloWallet': '#0085ca', - 'Heroku (light)': '#c7c5e6', - 'Heroku (dark)': '#6567a5', - 'HootSuite': '#003366', - 'Houzz': '#73ba37', - 'HTML5': '#ec6231', - 'IKEA': '#ffcc33', - 'IMDb': '#f3ce13', - 'Instagram': '#3f729b', - 'Intel': '#0071c5', - 'Intuit': '#365ebf', - 'Kickstarter': '#76cc1e', - 'kippt': '#e03500', - 'Kodery': '#00af81', - 'LastFM': '#c3000d', - 'LinkedIn': '#0e76a8', - 'Livestream': '#cf0005', - 'Lumo': '#576396', - 'Mixpanel': '#a086d3', - 'Meetup': '#e51937', - 'Nokia': '#183693', - 'NVIDIA': '#76b900', - 'Opera': '#cc0f16', - 'Path': '#e41f11', - 'PayPal (dark)': '#1e477a', - 'PayPal (light)': '#3b7bbf', - 'Pinboard': '#0000e6', - 'Pinterest': '#c8232c', - 'PlayStation': '#665cbe', - 'Pocket': '#ee4056', - 'Prezi': '#318bff', - 'Pusha': '#0f71b4', - 'Quora': '#a82400', - 'QUOTE.fm': '#66ceff', - 'Rdio': '#008fd5', - 'Readability': '#9c0000', - 'Red Hat': '#cc0000', - 'Resource': '#7eb400', - 'Rockpack': '#0ba6ab', - 'Roon': '#62b0d9', - 'RSS': '#ee802f', - 'Salesforce': '#1798c1', - 'Samsung': '#0c4da2', - 'Shopify': '#96bf48', - 'Skype': '#00aff0', - 'Snagajob': '#f47a20', - 'Softonic': '#008ace', - 'SoundCloud': '#ff7700', - 'Space Box': '#f86960', - 'Spotify': '#81b71a', - 'Sprint': '#fee100', - 'Squarespace': '#121212', - 'StackOverflow': '#ef8236', - 'Staples': '#cc0000', - 'Status Chart': '#d7584f', - 'Stripe': '#008cdd', - 'StudyBlue': '#00afe1', - 'StumbleUpon': '#f74425', - 'T-Mobile': '#ea0a8e', - 'Technorati': '#40a800', - 'The Next Web': '#ef4423', - 'Treehouse': '#5cb868', - 'Trulia': '#5eab1f', - 'Tumblr': '#34526f', - 'Twitch.tv': '#6441a5', - 'Twitter': '#00acee', - 'TYPO3': '#ff8700', - 'Ubuntu': '#dd4814', - 'Ustream': '#3388ff', - 'Verizon': '#ef1d1d', - 'Vimeo': '#86c9ef', - 'Vine': '#00a478', - 'Virb': '#06afd8', - 'Virgin Media': '#cc0000', - 'Wooga': '#5b009c', - 'WordPress (blue)': '#21759b', - 'WordPress (orange)': '#d54e21', - 'WordPress (grey)': '#464646', - 'Wunderlist': '#2b88d9', - 'XBOX': '#9bc848', - 'XING': '#126567', - 'Yahoo!': '#720e9e', - 'Yandex': '#ffcc00', - 'Yelp': '#c41200', - 'YouTube': '#c4302b', - 'Zalongo': '#5498dc', - 'Zendesk': '#78a300', - 'Zerply': '#9dcc7a', - 'Zootool': '#5e8b1d' -} - -// 生成一个随机的图片地址。 -// 替代图片源 -// http://fpoimg.com/ -// 参考自 -// http://rensanning.iteye.com/blog/1933310 -// http://code.tutsplus.com/articles/the-top-8-placeholders-for-web-designers--net-19485 -export const image = function (size, background, foreground, format, text) { +/** + * 随机生成一个图片,使用:https://dummyimage.com/,例如: + * https://dummyimage.com/600x400/cc00cc/470047.png&text=hello + * @param size 图片大小 + * @param background 背景色 + * @param foreground 文字颜色 + * @param format 图片格式 + * @param text 文字 + */ +export const image = function(size?: string, background?: string, foreground?: string, format?: string, text?: string): string { // Random.image( size, background, foreground, text ) if (arguments.length === 4) { text = format @@ -176,63 +29,85 @@ export const image = function (size, background, foreground, format, text) { text = foreground foreground = undefined } + // Random.image( size, text ) + if (arguments.length === 2) { + text = background + background = undefined + } // Random.image() - if (!size) size = helper.pick(_adSize) - - if (background && ~background.indexOf('#')) background = background.slice(1) - if (foreground && ~foreground.indexOf('#')) foreground = foreground.slice(1) - - // http://dummyimage.com/600x400/cc00cc/470047.png&text=hello - return 'http://dummyimage.com/' + size + (background ? '/' + background : '') + (foreground ? '/' + foreground : '') + (format ? '.' + format : '') + (text ? '&text=' + text : '') + size = size || helper.pick(_adSize) + + if (background && ~background.indexOf('#')) { + background = background.slice(1) + } + + if (foreground && ~foreground.indexOf('#')) { + foreground = foreground.slice(1) + } + + return ( + 'https://dummyimage.com/' + + size + + (background ? '/' + background : '') + + (foreground ? '/' + foreground : '') + + (format ? '.' + format : '') + + (text ? '&text=' + text : '') + ) } export const img = image -// 生成一段随机的 Base64 图片编码。 -// https://github.com/imsky/holder -export const dataImage = function (size, text) { - let canvas +/** + * 生成一个随机的base64图片 + * @param size 图片宽高 + * @param text 图片上的文字 + */ +export const dataImage = function(size?: string, text?: string): string { + size = size || helper.pick(_adSize) + text = text || size + const background: string = helper.pick([ + '#171515', '#e47911', '#183693', '#720e9e', '#c4302b', '#dd4814', + '#00acee', '#0071c5', '#3d9ae8', '#ec6231', '#003580', '#e51937' + ]) + const foreground = '#FFFFFF' + // browser if (typeof document !== 'undefined') { - canvas = document.createElement('canvas') + const canvas = document.createElement('canvas') + const ctx = canvas && canvas.getContext && canvas.getContext('2d') + if (!canvas || !ctx) { + return '' + } + + const sizeArr = size!.split('x') + const width = parseInt(sizeArr[0], 10) + const height = parseInt(sizeArr[1], 10) + + canvas.width = width + canvas.height = height + ctx.textAlign = 'center' + ctx.textBaseline = 'middle' + ctx.fillStyle = background + ctx.fillRect(0, 0, width, height) + ctx.fillStyle = foreground + ctx.font = 'bold 14px sans-serif' + ctx.fillText(text!, width / 2, height / 2, width) + return canvas.toDataURL('image/png') } else { - // https://github.com/Automattic/node-canvas - // npm install canvas --save - // 安装问题: - // * http://stackoverflow.com/questions/22953206/gulp-issues-with-cario-install-command-not-found-when-trying-to-installing-canva - // * https://github.com/Automattic/node-canvas/issues/415 - // * https://github.com/Automattic/node-canvas/wiki/_pages - // PS:node-canvas 的安装过程实在是太繁琐了,所以不放入 package.json 的 dependencies。 - const Canvas = module.require('canvas') - canvas = new Canvas() - } - - const ctx = canvas && canvas.getContext && canvas.getContext('2d') - if (!canvas || !ctx) { - return '' - } - - if (!size) { - size = helper.pick(_adSize) + try { + const request = require('sync-request') + const res = request('GET', image(size, background, foreground, text), { + cache: 'memory', + timeout: 8000 + }) + const buffer = res.getBody() + return 'data:image/png;base64,' + buffer.toString('base64') + } catch(err) { + if (err.toString().includes('timed out')) { + utils.logInfo('generate image timeout') + } else { + utils.logInfo(err) + } + return '' + } } - text = text !== undefined ? text : size - - size = size.split('x') - - const width = parseInt(size[0], 10) - const height = parseInt(size[1], 10) - const background = _brandColors[helper.pick(utils.keys(_brandColors))] - const foreground = '#FFF' - const text_height = 14 - const font = 'sans-serif' - - canvas.width = width - canvas.height = height - ctx.textAlign = 'center' - ctx.textBaseline = 'middle' - ctx.fillStyle = background - ctx.fillRect(0, 0, width, height) - ctx.fillStyle = foreground - ctx.font = 'bold ' + text_height + 'px ' + font - ctx.fillText(text, (width / 2), (height / 2), width) - return canvas.toDataURL('image/png') } diff --git a/src/lib/random/misc.ts b/src/lib/random/misc.ts index f9f1553..c0b7ed4 100755 --- a/src/lib/random/misc.ts +++ b/src/lib/random/misc.ts @@ -51,7 +51,10 @@ export const increment = function (step: number | string) { export const inc = increment -// 生成一个版本号 +/** + * 随机生成一个版本号 + * @param depth 版本号的层级,默认为3 + */ export const version = function (depth: number = 3): string { const numbers: number[] = [] for (let i = 0; i < depth; i++) { @@ -59,3 +62,16 @@ export const version = function (depth: number = 3): string { } return numbers.join('.') } + +// 随机生成一个中国手机号 +export const phone = function (): string { + const segments: string[] = [ + // 移动号段 + '134', '135', '136', '137', '138', '139', '147', '150', '151', '152', '157', '158', '159', '165', '172', '178', '182', '183', '184', '187', '188', + // 联通号段 + '130', '131', '132', '145', '155', '156', '171', '175', '176', '185', '186', + // 电信号段 + '133', '149', '153', '173', '174', '177', '180', '181', '189', '191' + ] + return helper.pick(segments) + basic.string('number', 8) +} diff --git a/src/lib/util.ts b/src/lib/util.ts index ef8e73d..2c0e50b 100755 --- a/src/lib/util.ts +++ b/src/lib/util.ts @@ -1,4 +1,4 @@ -export const objectAssign = function (target, varArgs) { +export const objectAssign = function (target, args) { // TypeError if undefined or null if (target == null) { throw new TypeError('Cannot convert undefined or null to object') @@ -6,8 +6,8 @@ export const objectAssign = function (target, varArgs) { let to = Object(target) - for (let index = 1; index < arguments.length; index++) { - const nextSource = arguments[index] + for (let i = 1; i < arguments.length; i++) { + const nextSource = arguments[i] if (nextSource != null) { // Skip over if undefined or null for (let nextKey in nextSource) { @@ -38,35 +38,37 @@ export const each = function (obj, iterator, context?) { } } -export const type = function (obj) { - return isDef(obj) ? Object.prototype.toString.call(obj).match(/\[object (\w+)\]/)![1].toLowerCase() : String(obj) +export const type = function(value: any): string { + return isDef(value) + ? Object.prototype.toString.call(value).match(/\[object (\w+)\]/)![1].toLowerCase() + : String(value) } export const isDef = function (value: any): boolean { return value !== undefined && value !== null } -export const isString = function (value) { +export const isString = function (value: any): value is string { return type(value) === 'string' } -export const isObject = function (value) { +export const isObject = function (value: any): value is object { return type(value) === 'object' } -export const isArray = function (value) { +export const isArray = function (value: any): value is Array { return type(value) === 'array' } -export const isRegExp = function (value) { +export const isRegExp = function (value: any): value is RegExp { return type(value) === 'regexp' } -export const isFunction = function (value) { +export const isFunction = function (value: any): value is Function { return type(value) === 'function' } -export const isObjectOrArray = function (value) { +export const isObjectOrArray = function (value: any): value is object | Array { return isObject(value) || isArray(value) } @@ -74,7 +76,7 @@ export const isNumeric = function (value) { return !isNaN(parseFloat(value)) && isFinite(value) } -export const keys = function (obj: object) { +export const keys = function (obj: object): string[] { const keys: string[] = [] for (let key in obj) { if (obj.hasOwnProperty(key)) { @@ -95,19 +97,9 @@ export const values = function (obj: object) { } /** - * ### Mock.heredoc(fn) - * + * Mock.heredoc(fn) * 以直观、安全的方式书写(多行)HTML 模板。 - * - * 使用示例如下所示: - * - * const tpl = Mock.heredoc(function () { - * - * }) - * - * 相关阅读: - * - * [Creating multiline strings in JavaScript](http://stackoverflow.com/questions/805107/creating-multiline-strings-in-javascript) + * http://stackoverflow.com/questions/805107/creating-multiline-strings-in-javascript */ export const heredoc = function (fn) { // 1. 移除起始的 function(){ /*! @@ -122,3 +114,7 @@ export const heredoc = function (fn) { } export const noop = function () {} + +export const logInfo = function (...args) { + console.log('[better-mock]', ...args) +} diff --git a/src/lib/xhr/index.ts b/src/lib/xhr/index.ts index a832441..ed17886 100755 --- a/src/lib/xhr/index.ts +++ b/src/lib/xhr/index.ts @@ -443,22 +443,46 @@ function find(options) { for (let sUrlType in MockXMLHttpRequest.Mock.mocked) { const item = MockXMLHttpRequest.Mock.mocked[sUrlType] if ( - (!item.rurl || match(item.rurl, options.url)) && - (!item.rtype || match(item.rtype, options.type.toLowerCase())) + (!item.rurl || matchUrl(item.rurl, options.url)) && + (!item.rtype || matchType(item.rtype, options.type)) ) { - // console.log('[mock]', options.url, '>', item.rurl) return item } } - function match(expected, actual) { - if (util.type(expected) === 'string') { - return expected === actual + function matchUrl(expected: string | RegExp, actual: string): boolean { + if (util.isString(expected)) { + if (expected === actual) { + return true + } + // expected: /hello/world + // actual: /hello/world?type=1 + if (actual.indexOf(expected) === 0 && actual[expected.length] === '?') { + return true + } } - if (util.type(expected) === 'regexp') { + if (util.isRegExp(expected)) { return expected.test(actual) } + return false + } + + function matchType(expected: string | RegExp, actual: string): boolean { + if (util.isString(expected) || util.isRegExp(expected)) { + return new RegExp(expected, 'i').test(actual) + } + return false } + + // function match(expected: string | RegExp, actual: string): boolean { + // if (util.isString(expected)) { + // return expected === actual + // } + // if (util.isRegExp(expected)) { + // return new RegExp(expected, 'i').test(actual) + // } + // return false + // } } // 数据模板 => 响应数据 diff --git a/test/test.mock.random.js b/test/test.mock.random.js index bdf6ff3..256c1f8 100755 --- a/test/test.mock.random.js +++ b/test/test.mock.random.js @@ -7,11 +7,12 @@ describe('Random', function () { return JSON.stringify(json /*, null, 4*/) } - function doit (expression, validator) { + function doit (expression, validator, cut) { it('', function () { const data = eval(expression) validator(data) - this.test.title = stringify(expression) + ' => ' + stringify(data) + const result = stringify(data) + this.test.title = `${stringify(expression)} => ${cut ? result.substr(0, 100) + '...' : result}` }) } @@ -46,7 +47,6 @@ describe('Random', function () { expect(+parts[1]).to.be.a('number').within(min, max) - /* jshint -W041 */ if (parts[2] != undefined) { expect(parts[2]).to.have.length.within(dmin, dmax) } @@ -208,23 +208,26 @@ describe('Random', function () { describe('Image', function () { doit('Random.image()', function (data) { - expect(data).to.be.ok - }) - it('Random.dataImage()', function () { - const data = eval(this.test.title) - expect(data).to.be.ok - this.test.title = stringify(this.test.title) + ' => ' - }) - it('Random.dataImage("200x100")', function () { - const data = eval(this.test.title) - expect(data).to.be.ok - this.test.title = stringify(this.test.title) + ' => ' - }) - it('Random.dataImage("200x100", "Hello Mock.js!")', function () { - const data = eval(this.test.title) - expect(data).to.be.ok - this.test.title = stringify(this.test.title) + ' => ' - }) + expect(data).to.include('https://dummyimage.com') + }) + doit('Random.image("300x400", "HelloWorld")', function (data) { + expect(data).to.be.equal('https://dummyimage.com/300x400&text=HelloWorld') + }) + doit('Random.image("300x400", "#234567", "HelloWorld")', function (data) { + expect(data).to.be.equal('https://dummyimage.com/300x400/234567&text=HelloWorld') + }) + doit('Random.image("300x400", "#234567", "#FFFFFF", "HelloWorld")', function (data) { + expect(data).to.be.equal('https://dummyimage.com/300x400/234567/FFFFFF&text=HelloWorld') + }) + doit('Random.dataImage()', function (data) { + expect(data.startsWith('data:image/png;base64,')).to.be.ok + }, true) + doit('Random.dataImage("200x100")', function (data) { + expect(data.startsWith('data:image/png;base64,')).to.be.ok + }, true) + doit('Random.dataImage("200x100", "HelloWorld")', function (data) { + expect(data.startsWith('data:image/png;base64,')).to.be.ok + }, true) }) const RE_COLOR = /^#[0-9a-fA-F]{6}$/ @@ -457,5 +460,10 @@ describe('Random', function () { expect(data).to.be.a('string') expect(data.split('.')).to.be.a('array').with.length(4) }) + doit('Random.phone()', function (data) { + expect(data).to.be.a('string') + const PHONE_RE = /^[1](([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}$/ + expect(PHONE_RE.test(data)).to.be.ok + }) }) }) diff --git a/test/test.mock.request.js b/test/test.mock.request.js index 7507209..71fd461 100755 --- a/test/test.mock.request.js +++ b/test/test.mock.request.js @@ -395,6 +395,72 @@ describe('Request', function () { }) }) + + describe('Mock.mock( rurl, rtype, function(options) ) + get params', function () { + it('', function (done) { + var that = this + var url = 'rurl_rtype_function.json' + + Mock.mock('rurl_rtype_function.json', 'get', function (options) { + expect(options).to.not.equal(undefined) + expect(options.url).to.be.equal(url + '?foo=1') + expect(options.type).to.be.equal('GET') + expect(options.body).to.be.equal(null) + return { + type: 'get' + } + }) + + $.ajax({ + url: url, + type: 'get', + dataType: 'json', + data: { + foo: 1 + } + }).done(function (data /*, status, jqXHR*/) { + that.test.title += 'GET ' + url + ' => ' + stringify(data) + expect(data).to.have.property('type', 'get') + }).fail(function (jqXHR, textStatus, errorThrown) { + console.log(jqXHR, textStatus, errorThrown) + }).always(function () { + done() + }) + }) + }) + + describe('Mock.mock( rurl, rtype, function(options) ) + method not case sensitive', function () { + it('', function (done) { + var that = this + var url = 'rurl_rtype_function.json' + + Mock.mock('rurl_rtype_function.json', 'GET', function (options) { + expect(options).to.not.equal(undefined) + expect(options.url).to.be.equal(url + '?foo=1') + expect(options.type).to.be.equal('GET') + expect(options.body).to.be.equal(null) + return { + type: 'get' + } + }) + + $.ajax({ + url: url, + type: 'get', + dataType: 'json', + data: { + foo: 1 + } + }).done(function (data /*, status, jqXHR*/) { + that.test.title += 'GET ' + url + ' => ' + stringify(data) + expect(data).to.have.property('type', 'get') + }).fail(function (jqXHR, textStatus, errorThrown) { + console.log(jqXHR, textStatus, errorThrown) + }).always(function () { + done() + }) + }) + }) describe('#105 addEventListener', function () { it('addEventListene => addEventListener', function (done) { var xhr = new Mock.XHR() diff --git a/test/test.mock.spec.dpd.js b/test/test.mock.spec.dpd.js index b255dba..5db2b41 100755 --- a/test/test.mock.spec.dpd.js +++ b/test/test.mock.spec.dpd.js @@ -197,6 +197,7 @@ describe('DPD', function () { id: '@ID', version1: '@VERSION', version2: '@VERSION(4)', + phone: '@PHONE', 'increment1|3': [ '@INCREMENT' ], diff --git a/typings/index.d.ts b/typings/index.d.ts new file mode 100644 index 0000000..29aacb4 --- /dev/null +++ b/typings/index.d.ts @@ -0,0 +1,282 @@ +// Type definitions for better-mock +// Project: http://github.com/lavyun/better-mock +// Definitions by: lavyun + +declare namespace betterMock { + type N = number; + type S = string; + type B = boolean; + + // Interface for global namespace 'betterMock' + interface BetterMock { + mock: Mock; + setup: Setup; + Random: Random; + valid: Valid; + toJSONSchema: ToJSONSchema; + version: number; + } + + interface MockCbOptions { + url: S; + type: S; + body: S | null; + } + + // Mock.mock() + interface Mock { + (rurl: S | RegExp, rtype: S, template: ((options: MockCbOptions) => any) | any): BetterMock; + + (rurl: S | RegExp, template: ((options: MockCbOptions) => any) | any): BetterMock; + + (template: any): any; + } + + interface SetupSettings { + timeout?: number | S; + } + + // Mock.setup() + type Setup = (settings: SetupSettings) => void; + + // Mock.Random - Basic + interface RandomBasic { + // Random.boolean + boolean(min: N, max: N, current: B): B; + boolean(): B; + + // Random.natural + natural(min?: N, max?: N): N; + + // Random.integer + integer(min?: N, max?: N): N; + + // Random.float + float(min?: N, max?: N, dmin?: N, dmax?: N): N; + + // Random.character + character(pool: 'lower' | 'upper' | 'number' | 'symbol'): S; + character(pool?: S): S; + + // Random.string + string(pool: S | N, min?: N, max?: N): S; + + // Random.range + range(start?: N, stop?: N, step?: N): N; + } + + // Mock.Random - Date + type RandomDateUtilString = 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second' | 'week'; + interface RandomDate { + // Random.date + date(format?: S): S; + + // Random.time + time(format?: S): S; + + // Random.datetime + datetime(format?: S): S; + + // Random.now + now(util: RandomDateUtilString, format?: S): S; + now(format?: S): S; + + // Random.timestamp + timestamp(): N; + } + + // Mock.Random - Image + interface RandomImage { + // Random.image + image(): S; + image(size: S, text: S): S; + image(size: S, background: S, text: S): S; + image(size: S, background: S, foreground: S, text: S); + image(size: S, background: S, foreground: S, format: 'png' | 'gif' | 'jpg', text: S): S; + + // Random.dataImage + dataImage(size?: S, text?: S): S; + } + + // Mock.Random - Color + interface RandomColor { + // Random.color + color(): S; + + // Random.hex + hex(): S; + + // Random.rgb + rgb(): S; + + // Random.rgba + rgba(): S; + + // Random.hsl + hsl(): S; + } + + // Mock.Random - Text + interface RandomText { + // Random.paragraph + paragraph(min?: N, max?: N): S; + + // Random.cparagraph + cparagraph(min?: N, max?: N): S; + + // Random.sentence + sentence(min?: N, max?: N): S; + + // Random.csentence + csentence(min?: N, max?: N): S; + + // Random.word + word(min?: N, max?: N): S; + + // Random.cword + cword(pool?: S | N, min?: N, max?: N): S; + + // Random.title + title(min?: N, max?: N): S; + + // Random.ctitle + ctitle(min?: N, max?: N): S; + } + + // Mock.Random - Name + interface RandomName { + // Random.first + first(): S; + + // Random.last + last(): S; + + // Random.name + name(middle?: B): S; + + // Random.cfirst + cfirst(): S; + + // Random.clast + clast(): S; + + // Random.cname + cname(): S; + } + + // Mock.Random - Web + type RandomWebProtocol = 'http' | 'ftp' | 'gopher' | 'mailto' | 'mid' | 'cid' | 'news' | 'nntp' | 'prospero' | 'telnet' | 'rlogin' | 'tn3270' | 'wais'; + interface RandomWeb { + // Random.url + url(protocol?: S, host?: S): S; + + // Random.protocol + protocol(): RandomWebProtocol; + + // Random.domain + domain(): S; + + // Random.tld + dtl(): S; + + // Random.email + email(domain?: S): S; + + // Random.ip + ip(): S; + } + + // Mock.Random - Address + interface RandomAddress { + // Random.region + region(): S; + + // Random.province + province(): S; + + // Random.city + city(prefix?: B): S; + + // Random.county + country(prefix?: B): S; + + // Random.zip + zip(prefix?: B): S; + } + + // Mock.Random - Helper + interface RandomHelper { + // Random.capitalize + capitalize(word: S): S; + + // Random.upper + upper(str: S): S; + + // Random.lower + lower(str: S): S; + + // Random.pick + pick(arr: any[]): any; + + // Random.shuffle + shuffle(arr: any[]): any[]; + } + + // Mock.Random - Miscellaneous + interface RandomMiscellaneous { + // Random.guid + guid(): S; + + // Random.id + id(): S; + + // Random.increment + increment(step?: N): N; + + // Random.version + version(depth?: N): S; + + // Random.phone + phone(): S; + } + + // Mock.Random + interface Random extends RandomBasic, RandomDate, + RandomImage, RandomColor, RandomAddress, + RandomHelper, RandomMiscellaneous, RandomName, + RandomText, RandomWeb { } + + interface ValidRsItem { + action: S; + actual: S; + expected: S; + message: S; + path: S[]; + type: S; + } + + // Mock.valid() + type Valid = (template: any, data: any) => ValidRsItem[]; + + interface ToJSONSchemaRs { + name: S | undefined; + template: any; + type: S; + rule: object; + path: S[]; + properties?: ToJSONSchemaRs[]; + items?: ToJSONSchemaRs[]; + } + + // Mock.toJSONSchema() + type ToJSONSchema = (template: any) => ToJSONSchemaRs; + + let mock: Mock; + let setup: Setup; + let Random: Random; + let valid: Valid; + let toJSONSchema: ToJSONSchema; + let version: number; +} + +export = betterMock;