vite-plugin-php
Version:
Process PHP-files with the speed and tools of Vite
1,593 lines (1,413 loc) • 324 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const node_child_process = require('node:child_process');
const node_url = require('node:url');
const node_path = require('node:path');
const require$$1 = require('net');
const require$$0 = require('util');
const require$$0$1 = require('tty');
const node_fs = require('node:fs');
const vite = require('vite');
const http = require('node:http');
const require$$0$2 = require('os');
const require$$0$3 = require('path');
const require$$0$4 = require('stream');
const require$$0$6 = require('events');
const require$$0$5 = require('fs');
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const require$$1__default = /*#__PURE__*/_interopDefaultCompat(require$$1);
const require$$0__default = /*#__PURE__*/_interopDefaultCompat(require$$0);
const require$$0__default$1 = /*#__PURE__*/_interopDefaultCompat(require$$0$1);
const http__default = /*#__PURE__*/_interopDefaultCompat(http);
const require$$0__default$2 = /*#__PURE__*/_interopDefaultCompat(require$$0$2);
const require$$0__default$3 = /*#__PURE__*/_interopDefaultCompat(require$$0$3);
const require$$0__default$4 = /*#__PURE__*/_interopDefaultCompat(require$$0$4);
const require$$0__default$6 = /*#__PURE__*/_interopDefaultCompat(require$$0$6);
const require$$0__default$5 = /*#__PURE__*/_interopDefaultCompat(require$$0$5);
const EPHPError = {
ERROR: 1,
WARNING: 2,
PARSE: 4,
NOTICE: 8,
CORE_ERROR: 16,
CORE_WARNING: 32,
COMPILE_ERROR: 64,
COMPILE_WARNING: 128,
USER_ERROR: 256,
USER_WARNING: 512,
USER_NOTICE: 1024,
STRICT: 2048,
RECOVERABLE_ERROR: 4096,
DEPRECATED: 8192,
USER_DEPRECATED: 16384,
ALL: 32767
};
const internalParam = "__314159265359__";
const shared = {
projectRoot: process.cwd(),
viteConfig: void 0,
devConfig: {
cleanup: true,
errorLevels: EPHPError.ALL | EPHPError.STRICT
},
entryPatterns: ["index.php"],
entries: ["index.php"],
tempDir: ".php-tmp"
};
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
function getAugmentedNamespace(n) {
if (Object.prototype.hasOwnProperty.call(n, '__esModule')) return n;
var f = n.default;
if (typeof f == "function") {
var a = function a () {
if (this instanceof a) {
return Reflect.construct(f, arguments, this.constructor);
}
return f.apply(this, arguments);
};
a.prototype = f.prototype;
} else a = {};
Object.defineProperty(a, '__esModule', {value: true});
Object.keys(n).forEach(function (k) {
var d = Object.getOwnPropertyDescriptor(n, k);
Object.defineProperty(a, k, d.get ? d : {
enumerable: true,
get: function () {
return n[k];
}
});
});
return a;
}
var picocolors = {exports: {}};
var hasRequiredPicocolors;
function requirePicocolors () {
if (hasRequiredPicocolors) return picocolors.exports;
hasRequiredPicocolors = 1;
let p = process || {}, argv = p.argv || [], env = p.env || {};
let isColorSupported =
!(!!env.NO_COLOR || argv.includes("--no-color")) &&
(!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || ((p.stdout || {}).isTTY && env.TERM !== "dumb") || !!env.CI);
let formatter = (open, close, replace = open) =>
input => {
let string = "" + input, index = string.indexOf(close, open.length);
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close
};
let replaceClose = (string, close, replace, index) => {
let result = "", cursor = 0;
do {
result += string.substring(cursor, index) + replace;
cursor = index + close.length;
index = string.indexOf(close, cursor);
} while (~index)
return result + string.substring(cursor)
};
let createColors = (enabled = isColorSupported) => {
let f = enabled ? formatter : () => String;
return {
isColorSupported: enabled,
reset: f("\x1b[0m", "\x1b[0m"),
bold: f("\x1b[1m", "\x1b[22m", "\x1b[22m\x1b[1m"),
dim: f("\x1b[2m", "\x1b[22m", "\x1b[22m\x1b[2m"),
italic: f("\x1b[3m", "\x1b[23m"),
underline: f("\x1b[4m", "\x1b[24m"),
inverse: f("\x1b[7m", "\x1b[27m"),
hidden: f("\x1b[8m", "\x1b[28m"),
strikethrough: f("\x1b[9m", "\x1b[29m"),
black: f("\x1b[30m", "\x1b[39m"),
red: f("\x1b[31m", "\x1b[39m"),
green: f("\x1b[32m", "\x1b[39m"),
yellow: f("\x1b[33m", "\x1b[39m"),
blue: f("\x1b[34m", "\x1b[39m"),
magenta: f("\x1b[35m", "\x1b[39m"),
cyan: f("\x1b[36m", "\x1b[39m"),
white: f("\x1b[37m", "\x1b[39m"),
gray: f("\x1b[90m", "\x1b[39m"),
bgBlack: f("\x1b[40m", "\x1b[49m"),
bgRed: f("\x1b[41m", "\x1b[49m"),
bgGreen: f("\x1b[42m", "\x1b[49m"),
bgYellow: f("\x1b[43m", "\x1b[49m"),
bgBlue: f("\x1b[44m", "\x1b[49m"),
bgMagenta: f("\x1b[45m", "\x1b[49m"),
bgCyan: f("\x1b[46m", "\x1b[49m"),
bgWhite: f("\x1b[47m", "\x1b[49m"),
blackBright: f("\x1b[90m", "\x1b[39m"),
redBright: f("\x1b[91m", "\x1b[39m"),
greenBright: f("\x1b[92m", "\x1b[39m"),
yellowBright: f("\x1b[93m", "\x1b[39m"),
blueBright: f("\x1b[94m", "\x1b[39m"),
magentaBright: f("\x1b[95m", "\x1b[39m"),
cyanBright: f("\x1b[96m", "\x1b[39m"),
whiteBright: f("\x1b[97m", "\x1b[39m"),
bgBlackBright: f("\x1b[100m", "\x1b[49m"),
bgRedBright: f("\x1b[101m", "\x1b[49m"),
bgGreenBright: f("\x1b[102m", "\x1b[49m"),
bgYellowBright: f("\x1b[103m", "\x1b[49m"),
bgBlueBright: f("\x1b[104m", "\x1b[49m"),
bgMagentaBright: f("\x1b[105m", "\x1b[49m"),
bgCyanBright: f("\x1b[106m", "\x1b[49m"),
bgWhiteBright: f("\x1b[107m", "\x1b[49m"),
}
};
picocolors.exports = createColors();
picocolors.exports.createColors = createColors;
return picocolors.exports;
}
var picocolorsExports = /*@__PURE__*/ requirePicocolors();
const colors = /*@__PURE__*/getDefaultExportFromCjs(picocolorsExports);
function hasViteConfig(input) {
if (!input || typeof input !== "object" || ["logger", "server"].some((key) => !(key in input))) {
throw new Error("Vite config not initialized!");
}
}
function log(message, { type = "info", prefix = true, ...options } = {}) {
hasViteConfig(shared.viteConfig);
let output = "";
if (prefix) {
output += colors.bgMagenta(colors.white("\u2009php\u2009")) + " ";
}
output += message;
shared.viteConfig.logger[type](output, options);
}
log.error = function(json, options = {}) {
let output = json;
let type = "info";
try {
const data = JSON.parse(json);
output = "";
switch (data.code) {
case EPHPError.PARSE:
case EPHPError.ERROR:
case EPHPError.CORE_ERROR:
case EPHPError.COMPILE_ERROR:
case EPHPError.USER_ERROR:
type = "error";
output += colors.bgRedBright(colors.white("Fatal Error"));
break;
case EPHPError.WARNING:
case EPHPError.USER_WARNING:
case EPHPError.COMPILE_WARNING:
case EPHPError.RECOVERABLE_ERROR:
type = "warn";
output += colors.yellowBright("Warning");
break;
case EPHPError.NOTICE:
case EPHPError.USER_NOTICE:
type = "info";
output += colors.bgWhite(colors.black("Notice"));
break;
case EPHPError.STRICT:
type = "info";
output += colors.yellow("Strict");
break;
case EPHPError.DEPRECATED:
case EPHPError.USER_DEPRECATED:
type = "info";
output += colors.cyan("Deprecated");
break;
default:
break;
}
output += " " + data.message + "\r\n";
output += " In: " + data.file.replace(
node_path.resolve(shared.tempDir),
shared.viteConfig?.root
) + "\r\n";
output += " On line: " + data.line;
} catch (error) {
}
log(output, { ...options, type });
};
var tcpPortUsed$1 = {};
var is2 = {};
var deepIs = {exports: {}};
var hasRequiredDeepIs;
function requireDeepIs () {
if (hasRequiredDeepIs) return deepIs.exports;
hasRequiredDeepIs = 1;
var pSlice = Array.prototype.slice;
var Object_keys = typeof Object.keys === 'function'
? Object.keys
: function (obj) {
var keys = [];
for (var key in obj) keys.push(key);
return keys;
}
;
var deepEqual = deepIs.exports = function (actual, expected) {
// enforce Object.is +0 !== -0
if (actual === 0 && expected === 0) {
return areZerosEqual(actual, expected);
// 7.1. All identical values are equivalent, as determined by ===.
} else if (actual === expected) {
return true;
} else if (actual instanceof Date && expected instanceof Date) {
return actual.getTime() === expected.getTime();
} else if (isNumberNaN(actual)) {
return isNumberNaN(expected);
// 7.3. Other pairs that do not both pass typeof value == 'object',
// equivalence is determined by ==.
} else if (typeof actual != 'object' && typeof expected != 'object') {
return actual == expected;
// 7.4. For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical 'prototype' property. Note: this
// accounts for both named and indexed properties on Arrays.
} else {
return objEquiv(actual, expected);
}
};
function isUndefinedOrNull(value) {
return value === null || value === undefined;
}
function isArguments(object) {
return Object.prototype.toString.call(object) == '[object Arguments]';
}
function isNumberNaN(value) {
// NaN === NaN -> false
return typeof value == 'number' && value !== value;
}
function areZerosEqual(zeroA, zeroB) {
// (1 / +0|0) -> Infinity, but (1 / -0) -> -Infinity and (Infinity !== -Infinity)
return (1 / zeroA) === (1 / zeroB);
}
function objEquiv(a, b) {
if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
return false;
// an identical 'prototype' property.
if (a.prototype !== b.prototype) return false;
//~~~I've managed to break Object.keys through screwy arguments passing.
// Converting to array solves the problem.
if (isArguments(a)) {
if (!isArguments(b)) {
return false;
}
a = pSlice.call(a);
b = pSlice.call(b);
return deepEqual(a, b);
}
try {
var ka = Object_keys(a),
kb = Object_keys(b),
key, i;
} catch (e) {//happens when one is a string literal and the other isn't
return false;
}
// having the same number of owned properties (keys incorporates
// hasOwnProperty)
if (ka.length != kb.length)
return false;
//the same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
//~~~cheap key test
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] != kb[i])
return false;
}
//equivalent values for every corresponding key, and
//~~~possibly expensive deep test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!deepEqual(a[key], b[key])) return false;
}
return true;
}
return deepIs.exports;
}
var ipRegex;
var hasRequiredIpRegex;
function requireIpRegex () {
if (hasRequiredIpRegex) return ipRegex;
hasRequiredIpRegex = 1;
const word = '[a-fA-F\\d:]';
const b = options => options && options.includeBoundaries ?
`(?:(?<=\\s|^)(?=${word})|(?<=${word})(?=\\s|$))` :
'';
const v4 = '(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}';
const v6seg = '[a-fA-F\\d]{1,4}';
const v6 = `
(?:
(?:${v6seg}:){7}(?:${v6seg}|:)| // 1:2:3:4:5:6:7:: 1:2:3:4:5:6:7:8
(?:${v6seg}:){6}(?:${v4}|:${v6seg}|:)| // 1:2:3:4:5:6:: 1:2:3:4:5:6::8 1:2:3:4:5:6::8 1:2:3:4:5:6::1.2.3.4
(?:${v6seg}:){5}(?::${v4}|(?::${v6seg}){1,2}|:)| // 1:2:3:4:5:: 1:2:3:4:5::7:8 1:2:3:4:5::8 1:2:3:4:5::7:1.2.3.4
(?:${v6seg}:){4}(?:(?::${v6seg}){0,1}:${v4}|(?::${v6seg}){1,3}|:)| // 1:2:3:4:: 1:2:3:4::6:7:8 1:2:3:4::8 1:2:3:4::6:7:1.2.3.4
(?:${v6seg}:){3}(?:(?::${v6seg}){0,2}:${v4}|(?::${v6seg}){1,4}|:)| // 1:2:3:: 1:2:3::5:6:7:8 1:2:3::8 1:2:3::5:6:7:1.2.3.4
(?:${v6seg}:){2}(?:(?::${v6seg}){0,3}:${v4}|(?::${v6seg}){1,5}|:)| // 1:2:: 1:2::4:5:6:7:8 1:2::8 1:2::4:5:6:7:1.2.3.4
(?:${v6seg}:){1}(?:(?::${v6seg}){0,4}:${v4}|(?::${v6seg}){1,6}|:)| // 1:: 1::3:4:5:6:7:8 1::8 1::3:4:5:6:7:1.2.3.4
(?::(?:(?::${v6seg}){0,5}:${v4}|(?::${v6seg}){1,7}|:)) // ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::1.2.3.4
)(?:%[0-9a-zA-Z]{1,})? // %eth0 %1
`.replace(/\s*\/\/.*$/gm, '').replace(/\n/g, '').trim();
// Pre-compile only the exact regexes because adding a global flag make regexes stateful
const v46Exact = new RegExp(`(?:^${v4}$)|(?:^${v6}$)`);
const v4exact = new RegExp(`^${v4}$`);
const v6exact = new RegExp(`^${v6}$`);
const ip = options => options && options.exact ?
v46Exact :
new RegExp(`(?:${b(options)}${v4}${b(options)})|(?:${b(options)}${v6}${b(options)})`, 'g');
ip.v4 = options => options && options.exact ? v4exact : new RegExp(`${b(options)}${v4}${b(options)}`, 'g');
ip.v6 = options => options && options.exact ? v6exact : new RegExp(`${b(options)}${v6}${b(options)}`, 'g');
ipRegex = ip;
return ipRegex;
}
const name = "is2";
const version = "2.0.9";
const description = "A type checking library where each exported function returns either true or false and does not throw. Also added tests.";
const license = "MIT";
const tags = [
"type",
"check",
"checker",
"checking",
"utilities",
"network",
"networking",
"credit",
"card",
"validation"
];
const keywords = [
"type",
"check",
"checker",
"checking",
"utilities",
"network",
"networking",
"credit",
"card",
"validation"
];
const author = "Enrico Marino <enrico.marino@email.com>";
const maintainers = "Edmond Meinfelder <edmond@stdarg.com>, Chris Oyler <christopher.oyler@gmail.com>";
const homepage = "http://github.com/stdarg/is2";
const repository = {
type: "git",
url: "git@github.com:stdarg/is2.git"
};
const bugs = {
url: "http://github.com/stdarg/is/issues"
};
const main = "./index.js";
const scripts = {
test: "./node_modules/.bin/mocha -C --reporter list tests.js"
};
const engines = {
node: ">=v0.10.0"
};
const dependencies = {
"deep-is": "^0.1.3",
"ip-regex": "^4.1.0",
"is-url": "^1.2.4"
};
const devDependencies = {
mocha: "6.2.3",
mongodb: "3.2.4"
};
const _package = {
name: name,
version: version,
description: description,
license: license,
tags: tags,
keywords: keywords,
author: author,
maintainers: maintainers,
homepage: homepage,
repository: repository,
bugs: bugs,
main: main,
scripts: scripts,
engines: engines,
dependencies: dependencies,
devDependencies: devDependencies
};
const _package$1 = {
__proto__: null,
author: author,
bugs: bugs,
default: _package,
dependencies: dependencies,
description: description,
devDependencies: devDependencies,
engines: engines,
homepage: homepage,
keywords: keywords,
license: license,
main: main,
maintainers: maintainers,
name: name,
repository: repository,
scripts: scripts,
tags: tags,
version: version
};
const require$$2 = /*@__PURE__*/getAugmentedNamespace(_package$1);
var isUrl_1;
var hasRequiredIsUrl;
function requireIsUrl () {
if (hasRequiredIsUrl) return isUrl_1;
hasRequiredIsUrl = 1;
/**
* Expose `isUrl`.
*/
isUrl_1 = isUrl;
/**
* RegExps.
* A URL must match #1 and then at least one of #2/#3.
* Use two levels of REs to avoid REDOS.
*/
var protocolAndDomainRE = /^(?:\w+:)?\/\/(\S+)$/;
var localhostDomainRE = /^localhost[\:?\d]*(?:[^\:?\d]\S*)?$/;
var nonLocalhostDomainRE = /^[^\s\.]+\.\S{2,}$/;
/**
* Loosely validate a URL `string`.
*
* @param {String} string
* @return {Boolean}
*/
function isUrl(string){
if (typeof string !== 'string') {
return false;
}
var match = string.match(protocolAndDomainRE);
if (!match) {
return false;
}
var everythingAfterProtocol = match[1];
if (!everythingAfterProtocol) {
return false;
}
if (localhostDomainRE.test(everythingAfterProtocol) ||
nonLocalhostDomainRE.test(everythingAfterProtocol)) {
return true;
}
return false;
}
return isUrl_1;
}
/**
* @fileOverview
* is2 derived from is by Enrico Marino, adapted for Node.js.
* Slightly modified by Edmond Meinfelder
*
* is
* the definitive JavaScript type testing library
* Copyright(c) 2013,2014 Edmond Meinfelder <edmond@stdarg.com>
* Copyright(c) 2011 Enrico Marino <enrico.marino@email.com>
* MIT license
*/
var hasRequiredIs2;
function requireIs2 () {
if (hasRequiredIs2) return is2;
hasRequiredIs2 = 1;
(function (exports) {
const owns = {}.hasOwnProperty;
const toString = {}.toString;
const is = exports;
const deepIs = requireDeepIs();
const ipRegEx = requireIpRegex();
is.version = require$$2.version;
////////////////////////////////////////////////////////////////////////////////
// Environment
/**
* Tests if is is running under a browser.
* @return {Boolean} true if the environment has process, process.version and process.versions.
*/
is.browser = function() {
return (!is.node() && typeof window !== 'undefined' && toString.call(window) === '[object global]');
};
/**
* Test if 'value' is defined.
* Alias: def
* @param {Any} value The value to test.
* @return {Boolean} true if 'value' is defined, false otherwise.
*/
is.defined = function(value) {
return typeof value !== 'undefined';
};
is.def = is.defined;
/**
* Tests if is is running under node.js
* @return {Boolean} true if the environment has process, process.version and process.versions.
*/
is.nodejs = function() {
return (process && process.hasOwnProperty('version') &&
process.hasOwnProperty('versions'));
};
is.node = is.nodejs;
/**
* Test if 'value' is undefined.
* Aliases: undef, udef
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is undefined, false otherwise.
*/
is.undefined = function(value) {
return value === undefined;
};
is.udef = is.undef = is.undefined;
////////////////////////////////////////////////////////////////////////////////
// Types
/**
* Test if 'value' is an array.
* Alias: ary, arry
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is an array, false otherwise.
*/
is.array = function(value) {
return '[object Array]' === toString.call(value);
};
is.arr = is.ary = is.arry = is.array;
/**
* Test if 'value' is an arraylike object (i.e. it has a length property with a valid value)
* Aliases: arraylike, arryLike, aryLike
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is an arguments object, false otherwise.
*/
is.arrayLike = function(value) {
if (is.nullOrUndef(value))
return false;
return value !== undefined &&
owns.call(value, 'length') &&
isFinite(value.length);
};
is.arrLike = is.arryLike = is.aryLike = is.arraylike = is.arrayLike;
/**
* Test if 'value' is an arguments object.
* Alias: args
* @param {Any} value value to test
* @return {Boolean} true if 'value' is an arguments object, false otherwise
*/
is.arguments = function(value) {
return '[object Arguments]' === toString.call(value);
};
is.args = is.arguments;
/**
* Test if 'value' is a boolean.
* Alias: bool
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is a boolean, false otherwise.
*/
is.boolean = function(value) {
return '[object Boolean]' === toString.call(value);
};
is.bool = is.boolean;
/**
* Test if 'value' is an instance of Buffer.
* Aliases: instOf, instanceof
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is an instance of 'constructor'.
*/
is.buffer = function(value) {
return is.nodejs() && Buffer && Buffer.hasOwnProperty('isBuffer') && Buffer.isBuffer(value);
};
is.buff = is.buf = is.buffer;
/**
* Test if 'value' is a date.
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is a date, false otherwise.
*/
is.date = function(value) {
return '[object Date]' === toString.call(value);
};
/**
* Test if 'value' is an error object.
* Alias: err
* @param value value to test.
* @return {Boolean} true if 'value' is an error object, false otherwise.
*/
is.error = function(value) {
return '[object Error]' === toString.call(value);
};
is.err = is.error;
/**
* Test if 'value' is false.
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is false, false otherwise
*/
is.false = function(value) {
return value === false;
};
/**
* Test if 'value' is a function or async function.
* Alias: func
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is a function, false otherwise.
*/
is.function = function(value) {
return is.syncFunction(value) || is.asyncFunction(value)
};
is.fun = is.func = is.function;
/**
* Test if 'value' is an async function using `async () => {}` or `async function () {}`.
* Alias: func
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is a function, false otherwise.
*/
is.asyncFunction = function(value) {
return '[object AsyncFunction]' === toString.call(value);
};
is.asyncFun = is.asyncFunc = is.asyncFunction;
/**
* Test if 'value' is a synchronous function.
* Alias: syncFunc
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is a function, false otherwise.
*/
is.syncFunction = function (value) {
return '[object Function]' === toString.call(value);
};
is.syncFun = is.syncFunc = is.syncFunction;
/**
* Test if 'value' is null.
* @param {Any} value to test.
* @return {Boolean} true if 'value' is null, false otherwise.
*/
is.null = function(value) {
return value === null;
};
/**
* Test is 'value' is either null or undefined.
* Alias: nullOrUndef
* @param {Any} value value to test.
* @return {Boolean} True if value is null or undefined, false otherwise.
*/
is.nullOrUndefined = function(value) {
return value === null || typeof value === 'undefined';
};
is.nullOrUndef = is.nullOrUndefined;
/**
* Test if 'value' is a number.
* Alias: num
* @param {Any} value to test.
* @return {Boolean} true if 'value' is a number, false otherwise.
*/
is.number = function(value) {
return '[object Number]' === toString.call(value);
};
is.num = is.number;
/**
* Test if 'value' is an object. Note: Arrays, RegExps, Date, Error, etc all return false.
* Alias: obj
* @param {Any} value to test.
* @return {Boolean} true if 'value' is an object, false otherwise.
*/
is.object = function(value) {
return '[object Object]' === toString.call(value);
};
is.obj = is.object;
/**
* Test if 'value' is a regular expression.
* Alias: regexp
* @param {Any} value to test.
* @return {Boolean} true if 'value' is a regexp, false otherwise.
*/
is.regExp = function(value) {
return '[object RegExp]' === toString.call(value);
};
is.re = is.regexp = is.regExp;
/**
* Test if 'value' is a string.
* Alias: str
* @param {Any} value to test.
* @return {Boolean} true if 'value' is a string, false otherwise.
*/
is.string = function(value) {
return '[object String]' === toString.call(value);
};
is.str = is.string;
/**
* Test if 'value' is true.
* @param {Any} value to test.
* @return {Boolean} true if 'value' is true, false otherwise.
*/
is.true = function(value) {
return value === true;
};
/**
* Test if 'value' is a uuid (v1-v5)
* @param {Any} value to test.
* @return {Boolean} true if 'value is a valid RFC4122 UUID. Case non-specific.
*/
var uuidRegExp = new RegExp('[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab]'+
'[0-9a-f]{3}-[0-9a-f]{12}', 'i');
is.uuid = function(value) {
return uuidRegExp.test(value);
};
////////////////////////////////////////////////////////////////////////////////
// Object Relationships
/**
* Test if 'value' is equal to 'other'. Works for objects and arrays and will do deep comparisions,
* using recursion.
* Alias: eq
* @param {Any} value value.
* @param {Any} other value to compare with.
* @return {Boolean} true if 'value' is equal to 'other', false otherwise
*/
is.equal = function(value, other) {
var type = toString.call(value);
if (typeof value !== typeof other) {
return false;
}
if (type !== toString.call(other)) {
return false;
}
if ('[object Object]' === type || '[object Array]' === type) {
return deepIs(value, other);
} else if ('[object Function]' === type) {
return value.prototype === other.prototype;
} else if ('[object Date]' === type) {
return value.getTime() === other.getTime();
}
return value === other;
};
is.objEquals = is.eq = is.equal;
/**
* JS Type definitions which cannot host values.
* @api private
*/
var NON_HOST_TYPES = {
'boolean': 1,
'number': 1,
'string': 1,
'undefined': 1
};
/**
* Test if 'key' in host is an object. To be hosted means host[value] is an object.
* @param {Any} value The value to test.
* @param {Any} host Host that may contain value.
* @return {Boolean} true if 'value' is hosted by 'host', false otherwise.
*/
is.hosted = function(value, host) {
if (is.nullOrUndef(value))
return false;
var type = typeof host[value];
return type === 'object' ? !!host[value] : !NON_HOST_TYPES[type];
};
/**
* Test if 'value' is an instance of 'constructor'.
* Aliases: instOf, instanceof
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is an instance of 'constructor'.
*/
is.instanceOf = function(value, constructor) {
if (is.nullOrUndef(value) || is.nullOrUndef(constructor))
return false;
return (value instanceof constructor);
};
is.instOf = is.instanceof = is.instanceOf;
/**
* Test if 'value' is an instance type objType.
* Aliases: objInstOf, objectinstanceof, instOf, instanceOf
* @param {object} objInst an object to testfor type.
* @param {object} objType an object type to compare.
* @return {Boolean} true if 'value' is an object, false otherwise.
*/
is.objectInstanceOf = function(objInst, objType) {
try {
return '[object Object]' === toString.call(objInst) && (objInst instanceof objType);
} catch(err) {
return false;
}
};
is.instOf = is.instanceOf = is.objInstOf = is.objectInstanceOf;
/**
* Test if 'value' is a type of 'type'.
* Alias: a
* @param value value to test.
* @param {String} type The name of the type.
* @return {Boolean} true if 'value' is an arguments object, false otherwise.
*/
is.type = function(value, type) {
return typeof value === type;
};
is.a = is.type;
////////////////////////////////////////////////////////////////////////////////
// Object State
/**
* Test if 'value' is empty. To be empty means to be an array, object or string with nothing contained.
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is empty, false otherwise.
*/
is.empty = function(value) {
var type = toString.call(value);
if ('[object Array]' === type || '[object Arguments]' === type) {
return value.length === 0;
}
if ('[object Object]' === type) {
for (var key in value) if (owns.call(value, key)) return false;
return true;
}
if ('[object String]' === type) {
return value === '';
}
return false;
};
/**
* Test if 'value' is an arguments object that is empty.
* Alias: args
* @param {Any} value value to test
* @return {Boolean} true if 'value' is an arguments object with no args, false otherwise
*/
is.emptyArguments = function(value) {
return '[object Arguments]' === toString.call(value) && value.length === 0;
};
is.noArgs = is.emptyArgs = is.emptyArguments;
/**
* Test if 'value' is an array containing no entries.
* Aliases: emptyArry, emptyAry
* @param {Any} value The value to test.
* @return {Boolean} true if 'value' is an array with no elemnets.
*/
is.emptyArray = function(value) {
return '[object Array]' === toString.call(value) && value.length === 0;
};
is.emptyArry = is.emptyAry = is.emptyArray;
/**
* Test if 'value' is an empty array(like) object.
* Aliases: arguents.empty, args.empty, ary.empty, arry.empty
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is an empty array(like), false otherwise.
*/
is.emptyArrayLike = function(value) {
return value.length === 0;
};
is.emptyArrLike = is.emptyArrayLike;
/**
* Test if 'value' is an empty string.
* Alias: emptyStr
* @param {Any} value to test.
* @return {Boolean} true if 'value' is am empty string, false otherwise.
*/
is.emptyString = function(value) {
return is.string(value) && value.length === 0;
};
is.emptyStr = is.emptyString;
/**
* Test if 'value' is an array containing at least 1 entry.
* Aliases: nonEmptyArry, nonEmptyAry
* @param {Any} value The value to test.
* @return {Boolean} true if 'value' is an array with at least 1 value, false otherwise.
*/
is.nonEmptyArray = function(value) {
return '[object Array]' === toString.call(value) && value.length > 0;
};
is.nonEmptyArr = is.nonEmptyArry = is.nonEmptyAry = is.nonEmptyArray;
/**
* Test if 'value' is an object with properties. Note: Arrays are objects.
* Alias: nonEmptyObj
* @param {Any} value to test.
* @return {Boolean} true if 'value' is an object, false otherwise.
*/
is.nonEmptyObject = function(value) {
return '[object Object]' === toString.call(value) && Object.keys(value).length > 0;
};
is.nonEmptyObj = is.nonEmptyObject;
/**
* Test if 'value' is an object with no properties. Note: Arrays are objects.
* Alias: nonEmptyObj
* @param {Any} value to test.
* @return {Boolean} true if 'value' is an object, false otherwise.
*/
is.emptyObject = function(value) {
return '[object Object]' === toString.call(value) && Object.keys(value).length === 0;
};
is.emptyObj = is.emptyObject;
/**
* Test if 'value' is a non-empty string.
* Alias: nonEmptyStr
* @param {Any} value to test.
* @return {Boolean} true if 'value' is a non-empty string, false otherwise.
*/
is.nonEmptyString = function(value) {
return is.string(value) && value.length > 0;
};
is.nonEmptyStr = is.nonEmptyString;
////////////////////////////////////////////////////////////////////////////////
// Numeric Types within Number
/**
* Test if 'value' is an even number.
* @param {Number} value to test.
* @return {Boolean} true if 'value' is an even number, false otherwise.
*/
is.even = function(value) {
return '[object Number]' === toString.call(value) && value % 2 === 0;
};
/**
* Test if 'value' is a decimal number.
* Aliases: decimalNumber, decNum
* @param {Any} value value to test.
* @return {Boolean} true if 'value' is a decimal number, false otherwise.
*/
is.decimal = function(value) {
return '[object Number]' === toString.call(value) && value % 1 !== 0;
};
is.dec = is.decNum = is.decimal;
/**
* Test if 'value' is an integer.
* Alias: integer
* @param {Any} value to test.
* @return {Boolean} true if 'value' is an integer, false otherwise.
*/
is.integer = function(value) {
return '[object Number]' === toString.call(value) && value % 1 === 0;
};
is.int = is.integer;
/**
* is.nan
* Test if `value` is not a number.
*
* @param {Mixed} value value to test
* @return {Boolean} true if `value` is not a number, false otherwise
* @api public
*/
is.notANumber = function(value) {
return !is.num(value) || value !== value;
};
is.nan = is.notANum = is.notANumber;
/**
* Test if 'value' is an odd number.
* @param {Number} value to test.
* @return {Boolean} true if 'value' is an odd number, false otherwise.
*/
is.odd = function(value) {
return !is.decimal(value) && '[object Number]' === toString.call(value) && value % 2 !== 0;
};
is.oddNumber = is.oddNum = is.odd;
////////////////////////////////////////////////////////////////////////////////
// Numeric Type & State
/**
* Test if 'value' is a positive number.
* Alias: positiveNum, posNum
* @param {Any} value to test.
* @return {Boolean} true if 'value' is a number, false otherwise.
*/
is.positiveNumber = function(value) {
return '[object Number]' === toString.call(value) && value > 0;
};
is.pos = is.positive = is.posNum = is.positiveNum = is.positiveNumber;
/**
* Test if 'value' is a negative number.
* Aliases: negNum, negativeNum
* @param {Any} value to test.
* @return {Boolean} true if 'value' is a number, false otherwise.
*/
is.negativeNumber = function(value) {
return '[object Number]' === toString.call(value) && value < 0;
};
is.neg = is.negNum = is.negativeNum = is.negativeNumber;
/**
* Test if 'value' is a negative integer.
* Aliases: negInt, negativeInteger
* @param {Any} value to test.
* @return {Boolean} true if 'value' is a negative integer, false otherwise.
*/
is.negativeInteger = function(value) {
return '[object Number]' === toString.call(value) && value % 1 === 0 && value < 0;
};
is.negativeInt = is.negInt = is.negativeInteger;
/**
* Test if 'value' is a positive integer.
* Alias: posInt
* @param {Any} value to test.
* @return {Boolean} true if 'value' is a positive integer, false otherwise.
*/
is.positiveInteger = function(value) {
return '[object Number]' === toString.call(value) && value % 1 === 0 && value > 0;
};
is.posInt = is.positiveInt = is.positiveInteger;
////////////////////////////////////////////////////////////////////////////////
// Numeric Relationships
/**
* Test if 'value' is divisible by 'n'.
* Alias: divisBy
* @param {Number} value value to test.
* @param {Number} n dividend.
* @return {Boolean} true if 'value' is divisible by 'n', false otherwise.
*/
is.divisibleBy = function(value, n) {
if (value === 0)
return false;
return '[object Number]' === toString.call(value) &&
n !== 0 &&
value % n === 0;
};
is.divBy = is.divisBy = is.divisibleBy;
/**
* Test if 'value' is greater than or equal to 'other'.
* Aliases: greaterOrEq, greaterOrEqual
* @param {Number} value value to test.
* @param {Number} other value to compare with.
* @return {Boolean} true, if value is greater than or equal to other, false otherwise.
*/
is.greaterOrEqualTo = function(value, other) {
return value >= other;
};
is.greaterOrEqual = is.ge = is.greaterOrEqualTo;
/**
* Test if 'value' is greater than 'other'.
* Aliases: greaterThan
* @param {Number} value value to test.
* @param {Number} other value to compare with.
* @return {Boolean} true, if value is greater than other, false otherwise.
*/
is.greaterThan = function(value, other) {
return value > other;
};
is.gt = is.greaterThan;
/**
* Test if 'value' is less than or equal to 'other'.
* Alias: lessThanOrEq, lessThanOrEqual
* @param {Number} value value to test
* @param {Number} other value to compare with
* @return {Boolean} true, if 'value' is less than or equal to 'other', false otherwise.
*/
is.lessThanOrEqualTo = function(value, other) {
return value <= other;
};
is.lessThanOrEq = is.lessThanOrEqual = is.le = is.lessThanOrEqualTo;
/**
* Test if 'value' is less than 'other'.
* Alias: lessThan
* @param {Number} value value to test
* @param {Number} other value to compare with
* @return {Boolean} true, if 'value' is less than 'other', false otherwise.
*/
is.lessThan = function(value, other) {
return value < other;
};
is.lt = is.lessThan;
/**
* Test if 'value' is greater than 'others' values.
* Alias: max
* @param {Number} value value to test.
* @param {Array} others values to compare with.
* @return {Boolean} true if 'value' is greater than 'others' values.
*/
is.maximum = function(value, others) {
if (!is.arrayLike(others) || !is.number(value))
return false;
var len = others.length;
while (--len > -1) {
if (value < others[len]) {
return false;
}
}
return true;
};
is.max = is.maximum;
/**
* Test if 'value' is less than 'others' values.
* Alias: min
* @param {Number} value value to test.
* @param {Array} others values to compare with.
* @return {Boolean} true if 'value' is less than 'others' values.
*/
is.minimum = function(value, others) {
if (!is.arrayLike(others) || !is.number(value))
return false;
var len = others.length;
while (--len > -1) {
if (value > others[len]) {
return false;
}
}
return true;
};
is.min = is.minimum;
/**
* Test if 'value' is within 'start' and 'finish'.
* Alias: withIn
* @param {Number} value value to test.
* @param {Number} start lower bound.
* @param {Number} finish upper bound.
* @return {Boolean} true if 'value' is is within 'start' and 'finish', false otherwise.
*/
is.within = function(value, start, finish) {
return value >= start && value <= finish;
};
is.withIn = is.within;
/**
* Test if 'value' is within 'precision' decimal places from 'comparitor'.
* Alias: closish, near.
* @param {Number} value value to test
* @param {Number} comparitor value to test 'value' against
* @param {Number} precision number of decimals to compare floating points, defaults to 2
* @return {Boolean} true if 'value' is within 'precision' decimal places from 'comparitor', false otherwise.
*/
is.prettyClose = function(value, comparitor, precision) {
if (!is.number(value) || !is.number(comparitor)) return false;
if (is.defined(precision) && !is.posInt(precision)) return false;
if (is.undefined(precision)) precision = 2;
return value.toFixed(precision) === comparitor.toFixed(precision);
};
is.closish = is.near = is.prettyClose;
////////////////////////////////////////////////////////////////////////////////
// Networking
/**
* Test if a value is a valid DNS address. eg www.stdarg.com is true while
* 127.0.0.1 is false.
* @param {Any} value to test if a DNS address.
* @return {Boolean} true if a DNS address, false otherwise.
* DNS Address is made up of labels separated by '.'
* Each label must be between 1 and 63 characters long
* The entire hostname (including the delimiting dots) has a maximum of 255 characters.
* Hostname may not contain other characters, such as the underscore character (_)
* other DNS names may contain the underscore.
*/
is.dnsAddress = function(value) {
if (!is.nonEmptyStr(value)) return false;
if (value.length > 255) return false;
if (numbersLabel.test(value)) return false;
if (!dnsLabel.test(value)) return false;
return true;
//var names = value.split('.');
//if (!is.array(names) || !names.length) return false;
//if (names[0].indexOf('_') > -1) return false;
//for (var i=0; i<names.length; i++) {
//if (!dnsLabel.test(names[i])) return false;
//}
//return true;
};
is.dnsAddr = is.dns = is.dnsAddress;
var dnsLabel = /^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$/;
var numbersLabel = /^([0-9]|[0-9][0-9\-]{0,61}[0-9])(\.([0-9]|[0-9][0-9\-]{0,61}[0-9]))*$/;
/**
* Test if value is a valid email address.
* @param {Any} value to test if an email address.
* @return {Boolean} true if an email address, false otherwise.
*/
is.emailAddress = function(value) {
if (!is.nonEmptyStr(value))
return false;
return emailRegexp.test(value);
};
is.email = is.emailAddr = is.emailAddress;
var emailRegexp = /^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*$/;
/**
* Test if a value is either an IPv4 numeric IP address.
* The rules are:
* must be a string
* length must be 15 characters or less
* There must be four octets separated by a '.'
* No octet can be less than 0 or greater than 255.
* @param {Any} value to test if an ip address.
* @return {Boolean} true if an ip address, false otherwise.
*/
is.ipv4Address = function(value) {
if (!is.nonEmptyStr(value)) return false;
if (value.length > 15) return false;
var octets = value.split('.');
if (!is.array(octets) || octets.length !== 4) return false;
for (var i=0; i<octets.length; i++) {
var val = parseInt(octets[i], 10);
if (isNaN(val)) return false;
if (val < 0 || val > 255) return false;
}
return true;
};
is.ipv4 = is.ipv4Addr = is.ipv4Address;
/**
* Test if a value is either an IPv6 numeric IP address.
* @param {Any} value to test if an ip address.
* @return {Boolean} true if an ip address, false otherwise.
*/
is.ipv6Address = function(value) {
if (!is.nonEmptyStr(value)) return false;
return ipRegEx.v6({extract: true}).test(value);
};
is.ipv6 = is.ipv6Addr = is.ipv6Address;
/**
* Test if a value is either an IPv4 or IPv6 numeric IP address.
* @param {Any} value to test if an ip address.
* @return {Boolean} true if an ip address, false otherwise.
*/
is.ipAddress = function(value) {
if (!is.nonEmptyStr(value)) return false;
return is.ipv4Address(value) || is.ipv6Address(value)
};
is.ip = is.ipAddr = is.ipAddress;
/**
* Test is a value is a valid ipv4, ipv6 or DNS name.
* Aliases: host, hostAddr, hostAddress.
* @param {Any} value to test if a host address.
* @return {Boolean} true if a host address, false otherwise.
*/
is.hostAddress = function(value) {
if (!is.nonEmptyStr(value)) return false;
return is.dns(value) || is.ipv4(value) || is.ipv6(value);
};
is.host = is.hostIp = is.hostAddr = is.hostAddress;
/**
* Test if a number is a valid TCP port
* @param {Any} value to test if its a valid TCP port
*/
is.port = function(value) {
if (!is.num(value) || is.negativeInt(value) || value > 65535)
return false;
return true;
};
/**
* Test if a number is a valid TCP port in the range 0-1023.
* Alias: is.sysPort.
* @param {Any} value to test if its a valid TCP port
*/
is.systemPort = function(value) {
if (is.port(value) && value < 1024)
return true;
return false;
};
is.sysPort = is.systemPort;
/**
* Test if a number is a valid TCP port in the range 1024-65535.
* @param {Any} value to test if its a valid TCP port
*/
is.userPort = function(value) {
if (is.port(value) && value > 1023)
return true;
return false;
};
/*
function sumDigits(num) {
var str = num.toString();
var sum = 0;
for (var i = 0; i < str.length; i++)
sum += (str[i]-0);
return sum;
}
*/
/**
* Test if a string is a credit card.
* From http://en.wikipedia.org/wiki/Luhn_algorithm
* @param {String} value to test if a credit card.
* @return true if the string is the correct format, false otherwise
*/
is.creditCardNumber = function(str) {
if (!is.str(str))
return false;
var ary = str.split('');
var i, cnt;
// From the rightmost digit, which is the check digit, moving left, double
// the value of every second digit;
for (i=ary.length-1, cnt=1; i>-1; i--, cnt++) {
if (cnt%2 === 0)
ary[i] *= 2;
}
str = ary.join('');
var sum = 0;
// if the product of the previous doubling operation is greater than 9
// (e.g., 7 * 2 = 14), then sum the digits of the products (e.g., 10: 1 + 0
// = 1, 14: 1 + 4 = 5). We do the this by joining the array of numbers and
// add adding the int value of all the characters in the string.
for (i=0; i<str.length; i++)
sum += Math.floor(str[i]);
// If the total (sum) modulo 10 is equal to 0 (if the total ends in zero)
// then the number is valid according to the Luhn formula; else it is not
// valid.
return sum % 10 === 0;
};
is.creditCard = is.creditCardNum = is.creditCardNumber;
////////////////////////////////////////////////////////////////////////////////
// The following credit card info is from:
// http://en.wikipedia.org/wiki/Bank_card_number#Issuer_identification_number_.28IIN.29
/**
* Test if card number is an American Express card.
* @param {String} the credit card number string to test.
* @return true if the string is the correct format, false otherwise
*/
is.americanExpressCardNumber = function(str) {
if (!is.str(str) || str.length !== 15)
return false;
var prefix = Math.floor(str.slice(0,2));
if (prefix !== 34 && prefix !== 37)
return false;
if (!is.creditCardNumber(str))
return false;
return true;
};
is.amexCard = is.amexCardNum = is.americanExpressCardNumber;
/**
* Test if card number is a China UnionPay card.
* @param {String} the credit card number string to test.
* @return true if the string is the correct format, false otherwise
*/
is.chinaUnionPayCardNumber = function(str) {
if (!is.str(str) || (str.length < 16 && str.length > 19))
return false;
var prefix = Math.floor(str.slice(0,2));
if (prefix !== 62 && prefix !== 88)
return false;
// no validation for this card
return true;
};
is.chinaUnion = is.chinaUnionPayCard = is.chinaUnionPayCardNumber;
/**
* Test if card number is a Diner's Club Carte Blance card.
* @param {String} the credit card number string to test.
* @return true if the string is the correct format, false otherwise
*/
is.dinersClubCarteBlancheCardNumber = function(str) {
if (!is.str(str) || str.length !== 14)
return false;
var prefix = Math.floor(str.slice(0,3));
if (prefix < 300 || prefix > 305)
return false;
if (!is.creditCardNumber(str))
return false;
return true;
};
is.dinersClubCB = is.dinersClubCarteBlancheCard =
is.dinersClubCarteBlancheCardNumber;
/**
* Test if card number is a Diner's Club International card.
* @param {String} the credit card number string to test.
* @return true if the string is the correct format, false otherwise
*/
is.dinersClubInternationalCardNumber = function(str) {
if (!is.str(str) || str.length !== 14)
return false;
var prefix = Math.floor(str.slice(0,3));
var prefix2 = Math.floor(str.slice(0,2));
// 300-305, 309, 36, 38-39
if ((prefix < 300 || prefix > 305) && prefix !== 309 && prefix2 !== 36 &&
(prefix2 < 38 || prefix2 > 39)) {
return false;
}
if (!is.creditCardNumber(str))
return false;
return true;
};
is.dinersClubInt = is.dinersClubInternationalCard =
is.dinersClubInternationalCardNumber;
/**
* Test if card number is a Diner's Club USA & CA card.
* @param {String} the credit card number string to test.
* @return true if the string is the correct format, false otherwise
*/
is.dinersClubUSACanadaCardNumber = function(str) {
if (!is.str(str) || str.length !== 16)
return false;
var prefix = Math.floor(str.slice(0,2));
if (prefix !== 54 && prefix !== 55)
return false;
if (!is.creditCardNumber(str))
return false;
return true;
};
is.dinersClub = is.dinersClubUSACanCard = is.dinersClubUSACanadaCardNumber;
/**
* Test if card number is a Diner's Club USA/CA card.
* @param {String} the credit card number string to test.
* @return true if the string is the correct format, false otherwise
*/
is.discoverCardNumber = function(str) {
if (!is.str(str) || str.length !== 16)
return false;
var prefix = Math.floor(str.slice(0,6));
var prefix2 = Math.floor(st