UNPKG

uupaa.webgldetector.js

Version:
1,314 lines (1,149 loc) 76.9 kB
// ['Reflection.js', 'Console.js', 'Valid.js', 'Help.js', 'Task.js', 'Test.js'].join() // Reflection.js (function(global) { "use strict"; // --- dependency modules ---------------------------------- // --- define / local variables ---------------------------- var IGNORE_KEYWORDS = [ "webkitStorageInfo", "Infinity", "NaN", "arguments", "caller", "callee", "buffer", "byteOffset", "byteLength", // DataView, ArrayBuffer, Float32Array, ... "length", "String.prototype.help", "Function.prototype.help", "MediaError", "webkitOfflineAudioContext", // OfflineAudioContext "webkitAudioContext", // AudioContext "webkitIDBTransaction", // IDBTransaction "webkitIDBRequest", // IDBRequest "webkitIDBObjectStore", // IDBObjectStore "webkitIDBKeyRange", // IDBKeyRange "webkitIDBIndex", // IDBIndex "webkitIDBFactory", // IDBFactory "webkitIDBDatabase", // IDBDatabase "webkitIDBCursor", // IDBCursor "webkitIndexedDB", // indexedDB "webkitURL", // URL ]; var _syntaxHighlightData = { matcher: null, // /^\W(function|var|...|with)\W$/ keywords: null // /\\[^\n]+|.../ }; var ES6_SYNTAX_KEYWORDS = [ "\/\/[^\n]+", // // comment "\/[^\n\/]+\/", // /regexp/ "\"[^\n\"]*\"", // "string" "\'[^\n\']*\'" // 'string' ]; var ES6_IDENTIFY_KEYWORD = "function|var|this|self|that|if|else|in|typeof|instanceof|null|undefined|" + "try|catch|throw|finally|switch|case|default|for|while|do|break|continue|" + "return|new|debugger|void|delete|" + "enum|class|super|extends|implements|interface|private|protected|package|" + "static|public|export|import|yield|let|const|with"; var functionCache = global["WeakMap"] ? new global["WeakMap"]() : null; // --- class / interfaces ---------------------------------- function Reflection() { } Reflection["lang"] = ""; // Reference language. "", "en", "ja" Reflection["addIgnoreKeyword"] = Reflection_addIgnoreKeyword; // Reflection.addIgnoreKeyword(keywords:StringArray):void // --- path --- Reflection["resolve"] = Reflection_resolve; // Reflection.resolve(target:Function|String):Object // --- module --- Reflection["getModuleRepository"] = Reflection_getModuleRepository; // Reflection.getModuleRepository(moduleName:String):String // --- class --- Reflection["getBaseClassName"] = Reflection_getBaseClassName; // Reflection.getBaseClassName(value):String Reflection["getConstructorName"] = Reflection_getConstructorName; // Reflection.getConstructorName(value):String // --- function --- Reflection["parseFunction"] = Reflection_parseFunction; // Reflection.parseFunction(target:Function):Object Reflection["buildFunction"] = Reflection_buildFunction; // Reflection.buildFunction(declaration:Object):String // --- link --- Reflection["getSearchLink"] = Reflection_getSearchLink; // Reflection.getSearchLink(path:String):Object Reflection["getReferenceLink"] = Reflection_getReferenceLink; // Reflection.getReferenceLink(path:String):Object // --- syntax highlight --- Reflection["syntaxHighlight"] = Reflection_syntaxHighlight; // Reflection.syntaxHighlight(code:String, highlight:String, target:String = "console", style:Object = {}):StringArray // --- implements ------------------------------------------ function Reflection_addIgnoreKeyword(keywords) { // @arg StringArray // @desc add ignore keywords. Array.prototype.push.apply(IGNORE_KEYWORDS, keywords); } function Reflection_resolve(target) { // @arg Function|String target function - Object.freeze or "Object.freeze" // callback(detach:Boolean):void // @ret Object - { path, fn } // @return.path String - function absoulute path. eg: ["Object", "freeze"] // @return.fn Function - function. eg: Object.freeze // @desc resolve function absolute path. //{@dev if (!/function|string/.test(typeof target)) { throw new Error("Reflection.resolve(target): target is not Function or String."); } //}@dev var path = ""; var fn = null; switch (typeof target) { case "function": path = _convertFunctionToPathString(global, target, ["Object", "Function", "Array", "String", "Number"]) || // inject _convertFunctionToPathString(global.WebModule, target, []); // inject fn = target; break; case "string": target = _extractSharp(target); path = target; fn = _convertPathStringToFunction(target); if (!fn) { fn = _convertPathStringToFunction("WebModule." + target); if (fn) { path = "WebModule." + target; } } } return { "path": path, "fn": fn }; } function _convertPathStringToFunction(target) { // @arg String - function path. "Object.freeze" // @ret Function|null - function object. Object.freeze return target.split(".").reduce(function(parent, token) { return ( parent && (token in parent) ) ? parent[token] : null; }, global); } function _convertFunctionToPathString(root, // @arg Object - find root object. global or global.WebModule target, // @arg Function - function object. Object.freeze injectKeys) { // @arg StringArray - ["Object", "Function", ...] // @ret String - function path. "Object.freeze" var path = ""; var rootKeys = _enumKeys(root).sort(); Array.prototype.unshift.apply(rootKeys, injectKeys); for (var i = 0, iz = rootKeys.length; i < iz && !path; ++i) { var className = rootKeys[i]; if ( IGNORE_KEYWORDS.indexOf(className) < 0 && root[className] != null && /object|function/.test(typeof root[className]) ) { var klass = root[className]; if (klass === target) { path = className; } else { path = _findClassMember(target, root, className, _enumKeys(klass)); if ( !path && ("prototype" in klass) ) { path = _findPropertyMember(target, root, className, _enumKeys(klass["prototype"])); } } } } return path.replace(/^global\./i, ""); } function _enumKeys(object) { return (Object["getOwnPropertyNames"] || Object["keys"])(object); } function _findClassMember(target, root, className, keys) { for (var i = 0, iz = keys.length; i < iz; ++i) { var key = keys[i]; var path = className + "." + key; if (IGNORE_KEYWORDS.indexOf(path) < 0 && IGNORE_KEYWORDS.indexOf(key) < 0) { try { if (root[className][key] === target) { return path; // resolved } } catch (o_o) {} } } return ""; } function _findPropertyMember(target, root, className, keys) { for (var i = 0, iz = keys.length; i < iz; ++i) { var key = keys[i]; var path = className + ".prototype." + key; if (IGNORE_KEYWORDS.indexOf(path) < 0 && IGNORE_KEYWORDS.indexOf(key) < 0) { try { if (root[className]["prototype"][key] === target) { return path; // resolved } } catch (o_o) {} } } return ""; } function Reflection_parseFunction(target) { // @arg Function // @ret Object - { name:String, head:StringArray, body:StringArray, arg:StringArray, ret:StringArray } if (functionCache && functionCache.has(target)) { return functionCache.get(target); } var result = _splitFunctionDeclaration(target + ""); // { head, body } result["name"] = target["name"]; result["arg"] = _getArg(result["head"]); result["ret"] = _getRet(result["head"]); if (functionCache) { functionCache.set(target, result); } return result; } function Reflection_buildFunction(declaration) { // @arg Object - { head, body, arg, ret } return ""; // TODO impl } function _getArg(head) { // @arg StringArray - [line, ...] // @ret Object - [{ name, type, optional, comment }, ...] // get @arg attribute. // // function Foo_add(name, // @arg Function|String = "" comment // key ) { // @arg String comment // // @ret ResultType comment // ~~~~~ ~~~~~~~~~~~~~~~ ~~ ~~~~~~~ // name type opt comment // } var result = []; var format = /^([\w\|\/,]+)\s*(=\s*("[^"]*"|'[^']*'|\S+))?\s*([^\n]*)$/; head.forEach(function(line, lineNumber) { if (/@arg|@var_args/.test(line)) { if (lineNumber === 0) { line = _removeFunctionDeclarationString(line); } var nameType = line.split(/@arg|@var_args/); var name = nameType[0].replace(/\W+/g, "").trim(); var type = ""; var optional = ""; var comment = ""; var token = format.exec(nameType[1].trim()); if (token) { type = token[1]; optional = token[3] || ""; comment =(token[4] || "").replace(/^[ :#\-]+/, ""); } result.push({ "name": name, "type": type, "optional": optional, "comment": comment }); } }); return result; } function _getRet(head) { // @arg StringArray - [line, ...] // @ret Object - [{ types, comment }, ...] // get @ret attribute. // // function Foo_add(name, // @arg Function|String = "" comment // key ) { // @arg String comment // // @ret ResultType comment // ~~~~~~~~~~~~~~~ ~~~~~~~ // type comment // } var result = []; var format = /^([\w\|\/,]+)\s+([^\n]*)$/; head.forEach(function(line, lineNumber) { if (/@ret/.test(line)) { if (lineNumber === 0) { line = _removeFunctionDeclarationString(line); } var typeComment = line.split(/@ret/); // -> [" // ", " ResultType comment"] var type = ""; var comment = ""; var token = format.exec(typeComment[1].trim()); if (token) { type = token[1]; comment =(token[2] || "").replace(/^[ :#\-]+/, ""); } result.push({ "type": type, "comment": comment }); } }); return result; } function _splitFunctionDeclaration(sourceCode) { // @arg String - function code // @ret Object - { head:StringArray, body:StringArray } // // sourceCode: // // "function foo() { // @ret String\n // return '';\n // }" // // result: { // head: [ // "function foo() { // @ret String" // ], // body: [ // " return '';", // "}" // ] // } // var code = sourceCode.trim(); var lines = code.split("\n"); var basePos = lines[0].indexOf("//"); var min = 10; if (basePos >= min) { // "function foo() {" for (var i = 1, iz = lines.length; i < iz; ++i) { var pos = lines[i].indexOf("//"); // get header comment position(column) if (pos < min || pos < basePos) { break; } } } return { "head": lines.slice(0, i), "body": lines.slice(i) }; } function _removeFunctionDeclarationString(sourceCode) { // @arg String // @ret String // // sourceCode: // "function xxx(...) { }" // // result: // "(...) { }" // return sourceCode.replace(/^function\s+[^\x28]+/, ""); } function _extractSharp(path) { // @arg String - "Array#forEach" // @ret String - "Array.prototype.forEach" return path.trim().replace("#", ".prototype."); } function Reflection_getModuleRepository(moduleName) { // @arg String - path. "Reflection" // @ret String // @desc get WebModule repository url. if (moduleName in global["WebModule"]) { var repository = global["WebModule"][moduleName]["repository"] || ""; if (repository) { return repository.replace(/\/+$/, ""); // trim tail slash } } if (moduleName in global) { var repository = global[moduleName]["repository"] || ""; if (repository) { return repository.replace(/\/+$/, ""); // trim tail slash } } return ""; // global["WebModule"][moduleName] or global[moduleName] not found } function Reflection_getSearchLink(path) { // @arg String - "Object.freeze" // @ret Object - { title:String, url:URLString } // @desc get Google search link. // // Google Search( Array.isArray ): // http://www.google.com/search?lr=lang_ja&ie=UTF-8&oe=UTF-8&q=Array.isArray // return { "title": "Google Search( " + path + " ):", "url": _createGoogleSearchURL(path) }; } function _createGoogleSearchURL(keyword) { // @arg String - search keyword. // @ret String - "http://..." return "http://www.google.com/search?lr=lang_" + _getLanguage() + "&q=" + encodeURIComponent(keyword); } function Reflection_getReferenceLink(path) { // @arg String - "Object.freeze" // @ret Object - { title:String, url:URLString } // @desc get JavaScript/WebModule reference link. if ( /^WebModule\./.test(path) ) { path = path.replace(/^WebModule\./, ""); } var className = path.split(".")[0] || ""; // "Array.prototype.forEach" -> ["Array", "prototype", "forEach"] -> "Array" var repository = Reflection_getModuleRepository(className); // "https://github.com/uupaa/Help.js" // // JavaScript API( Array.isArray ) Reference: // http://www.google.com/search?btnI=I%27m+Feeling+Lucky&lr=lang_ja&ie=UTF-8&oe=UTF-8&q=MDN%20Array.isArray // // WebModule Reference: // https://github.com/uupaa/PageVisibilityEvent.js/wiki/PageVisibilityEvent# // if (/native code/.test(global[className] + "")) { return { "title": "JavaScript Reference( " + path + " ):", "url": _createGoogleImFeelingLuckyURL(path, "MDN") }; } else if (repository && /github/i.test(repository)) { return { "title": "WebModule Reference:", "url": _createGitHubWikiURL(repository, className, path) }; } return null; } function _createGoogleImFeelingLuckyURL(keyword, // @arg String - search keyword. provider) { // @arg String - search providoer. // @ret String - "http://..." // @desc create I'm feeling lucky url return "http://www.google.com/search?btnI=I%27m+Feeling+Lucky&lr=lang_" + _getLanguage() + "&q=" + provider + "%20" + encodeURIComponent(keyword); } function _createGitHubWikiURL(baseURL, // @arg String - "http://..." wikiPageName, // @arg String - "Foo" hash) { // @arg String - "Foo#add" // replace characters // space -> "-" // hyphen -> "-" // underbar -> "_" // alphabet -> alphabet // number -> number // other -> "" // unicode -> encodeURIComponent(unicode) hash = hash.replace(/[\x20-\x7e]/g, function(match) { var result = / |-/.test(match) ? "-" : /\W/.test(match) ? "" : match; return result; }); // {baseURL}/wiki/{wikiPageName} or // {baseURL}/wiki/{wikiPageName}#{hash} var result = []; result.push( baseURL.replace(/\/+$/, ""), // remove tail slash "/wiki/", wikiPageName + "#" ); if (wikiPageName !== hash) { result.push( "wiki-", encodeURIComponent(hash.toLowerCase()) ); } return result.join(""); } function _getLanguage() { // @ret String - "en", "ja" ... if (Reflection["lang"]) { return Reflection["lang"]; } if (global["navigator"]) { return global["navigator"]["language"]; } return "en"; } function Reflection_getBaseClassName(value) { // @arg Any - instance, exclude null and undefined. // @ret String // Object.prototype.toString.call(new Error()); -> "[object Error]" // Object.prototype.toString.call(new TypeError()); -> "[object Error]" return Object.prototype.toString.call(value).split(" ")[1].slice(0, -1); // -> "Error" } function Reflection_getConstructorName(value) { // @arg Any - instance, exclude null and undefined. // @ret String // Reflection_getConstructorName(new (function Aaa() {})); -> "Aaa" return value.constructor["name"] || (value.constructor + "").split(" ")[1].split("\x28")[0]; // for IE } function Reflection_syntaxHighlight(code, // @arg String - source code highlight, // @arg String - highlight keyword target, // @arg String = "console" - target environment. style) { // @arg Object = {} - { syntax, comment, literal, highlight } // @style.syntax CSSStyleTextString = "color:#03f" // @style.comment CSSStyleTextString = "color:#3c0" // @style.literal CSSStyleTextString = "color:#f6c" // @style.highlight CSSStyleTextString = "background:#ff9;font-weight:bold" // @ret StringArray switch (target || "console") { case "console": return _syntaxHighlightForConsole(code, highlight, style || {}); } return []; } function _syntaxHighlightForConsole(code, highlight, style) { var styleSyntax = style["syntax"] || "color:#03f"; var styleComment = style["comment"] || "color:#3c0"; var styleLiteral = style["literal"] || "color:#f6c"; var styleHighlight = style["highlight"] || "background:#ff9;font-weight:bold"; var highlightData = _createSyntaxHighlightData(); var styleDeclaration = []; var rexSource = highlight ? (highlight + "|" + highlightData.keyword.join("|")) : highlightData.keyword.join("|"); var rex = new RegExp("(" + rexSource + ")", "g"); var body = ("\n" + code + "\n").replace(/%c/g, "% c"). replace(rex, function(_, match) { if (match === highlight) { styleDeclaration.push(styleHighlight, ""); return "%c" + highlight + "%c"; } else if (/^\/\/[^\n]+$/.test(match)) { styleDeclaration.push(styleComment, ""); return "%c" + match + "%c"; } else if (/^(\/[^\n\/]+\/|\"[^\n\"]*\"|\'[^\n\']*\')$/.test(match)) { styleDeclaration.push(styleLiteral, ""); return "%c" + match + "%c"; } else if (highlightData.matcher.test(match)) { styleDeclaration.push(styleSyntax, ""); return "%c" + match + "%c"; } return match; }).trim(); return [body].concat(styleDeclaration); } function _createSyntaxHighlightData() { if (!_syntaxHighlightData.matcher) { // cached? _syntaxHighlightData.matcher = new RegExp("^\\W(" + ES6_IDENTIFY_KEYWORD + ")\\W$"); _syntaxHighlightData.keyword = [].concat(ES6_SYNTAX_KEYWORDS, ES6_IDENTIFY_KEYWORD.split("|").map(function(keyword) { return "\\W" + keyword + "\\W"; })); } return _syntaxHighlightData; } // --- exports --------------------------------------------- if (typeof module !== "undefined") { module["exports"] = Reflection; } global["Reflection"] = Reflection; })(GLOBAL); // Console.js (function(global) { "use strict"; // --- dependency modules ---------------------------------- // --- define / local variables ---------------------------- var CONSOLE_COLORS = { BLACK: "\u001b[30m", RED: "\u001b[31m", GREEN: "\u001b[32m", YELLOW: "\u001b[33m", BLUE: "\u001b[34m", MAGENTA:"\u001b[35m", CYAN: "\u001b[36m", WHITE: "\u001b[37m", CLEAR: "\u001b[0m" }; // --- class / interfaces ---------------------------------- var Console = { "log": Console_log, // Console.log(...:Any):void "warn": Console_warn, // Console.warn(...:Any):void "error": Console_error, // Console.error(...:Any):void "color": Console_color, // Console.color(color:ColorString, message:String):void "link": Console_link, // Console.link(url:String, title:String = "", style:Object = null):void "isEnabledStyle": Console_isEnabledStyle, // Console.isEnabledStyle():Boolean }; // --- implements ------------------------------------------ function Console_log() { console.log.apply(console, arguments); } function Console_warn() { console.warn.apply(console, arguments); } function Console_error() { console.error.apply(console, arguments); } function Console_color(color, // @arg ColorString message) { // @arg String if ( Console_isEnabledStyle() ) { color = color.toUpperCase(); if (color in CONSOLE_COLORS) { console.log("%c" + message, "color:" + color, ""); } } else if (IN_NODE) { color = color.toUpperCase(); if (color in CONSOLE_COLORS) { console.log(CONSOLE_COLORS[color] + message + CONSOLE_COLORS.CLEAR); } } else { console.log(message); } } function Console_link(url, // @arg URLString title, // @arg String = "" style) { // @arg Object - { link, mark } // @style.link String = "border-bottom:2px solid #9ff" // @style.mark String = "▶" title = title || ""; style = style || {}; var linkStyle = style["link"] || "border-bottom:2px solid #9ff"; var mark = style["mark"] || "\u25b6"; if ( Console_isEnabledStyle() ) { console.log.apply( console, _stylishLink(url, title, linkStyle, mark) ); } else { console.log(title + url); } } function _stylishLink(url, title, linkStyle, mark) { if (!/%/.test(url)) { var link = ""; if (title) { link = mark + " " + title + "\n %c" + url + "%c"; } else { link = "%c" + url + "%c"; } return [link].concat([linkStyle, ""]); } return [title, url]; } function Console_isEnabledStyle() { // @ret Boolean if (global["navigator"]) { if ( /Chrome/.test( global["navigator"]["userAgent"] || "" ) ) { if (IN_BROWSER) { return true; } } } return false; } if (console && !console.table) { console.table = console.dir; } // --- exports --------------------------------------------- if (typeof module !== "undefined") { module["exports"] = Console; } global["Console"] = Console; })(GLOBAL); // Valid.js (function(global) { "use strict"; // --- dependency modules ---------------------------------- // --- define / local variables ---------------------------- var TYPED_ARRAYS = [ "Int8Array", "Uint8Array", "Uint8ClampedArray", "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float32Array", "Float64Array" ]; var SPLITTER = /,|\x7c|\x2f/; // Value.keys(value, "a,b|c/d") var TYPE_SYNONYMS = { //informal formal "omit": "Omit", "null": "Null", "void": "Undefined", "Void": "Undefined", "undefined":"Undefined", "INTEGER": "Integer", "INT32": "Int32", "INT16": "Int16", "INT8": "Int8", "UINT32": "Uint32", "UINT16": "Uint16", "UINT8": "Uint8", "percent": "Percent", }; var _hook = {}; // { type: callback, ... } // --- class / interfaces ---------------------------------- function Valid(value, // @arg Boolean api, // @arg Function highlihgt) { // @arg String = "" if (!value) { if (global["Help"]) { global["Help"](api, highlihgt || ""); } throw new Error("Validation Error: " + api["name"] + "(" + highlihgt + ") is invalid value."); } } Valid["repository"] = "https://github.com/uupaa/Valid.js"; Valid["args"] = Valid_args; // Valid.args(api:Function, args:Array|ArrayLike):void Valid["type"] = Valid_type; // Valid.type(value:Any, types:String):Boolean Valid["some"] = Valid_some; // Valid.some(value:String|null|undefined, candidate:String|Object, ignoreCase:Boolean = false):Boolean Valid["keys"] = Valid_keys; // Valid.keys(object:Object|Array|null|undefined, key:String):Boolean Valid["values"] = Valid_values; // Valid.values(object:Object|Array|null|undefined, value:Array):Boolean Valid["json"] = Valid_json; // Valid.json(json:Object, scheme:Object):Boolean Valid["stack"] = Valid_stack; // Valid.stack(message:String = "", depth:Integer = 3):String // --- extension --- Valid["register"] = Valid_register; // Valid.register(type:HookTypeString, callback:Function):void Valid["unregister"] = Valid_unregister; // Valid.unregister(type:HookTypeString):void Valid["isRegistered"] = Valid_isRegistered; // Valid.isRegistered(type:HookTypeString):Boolean // --- implements ------------------------------------------ function Valid_args(api, // @arg Function args) { // @arg Array|ArrayLike if (global["Reflection"]) { var func = global["Reflection"]["parseFunction"](api); //global["Reflection"]["buildFunction"](func); func["arg"].forEach(function(item, index) { var type = item["type"]; if (item["optional"]) { type += "|omit"; } if ( !Valid_type(args[index], type) ) { if (global["Help"]) { global["Help"](api, item["name"]); } throw new Error(api["name"] + "(" + item["name"] + ") is invalid type."); } }); } } function Valid_type(value, // @arg Any types) { // @arg TypeNameString - "Type1", "Type1|Type2|omit" // NativeTypeNameString: Array, Number, null ... // SpecialTypeNameString: Integer, TypedArray, omit ... // ComplexTypeNameString: URLString, FunctionArray ... // @ret Boolean if (arguments.length >= 3) { throw new Error("The maximum length of Valid.type arguments are 2."); } return types.split(SPLITTER).some(_some); function _some(type) { // @arg NativeTypeNameString|SpecialTypeNameString|ComplexTypeNameString // @ret Boolean type = TYPE_SYNONYMS[type] || type; // --- special keywords --- switch (type) { case "Any": return true; case "this": return value instanceof global[_getBaseClassName(value)]; case "Omit": return value === null || value === undefined; case "TypedArray": return _isTypedArray(value); case "Null": return value === null; case "Undefined": return value === undefined; case "Array": return Array.isArray(value); case "Object": return _isObject(value || 0); case "FunctionArray": return Array.isArray(value) && _isFunctionArray(value); case "Percent": return _isNumber(value) && value >= 0.0 && value <= 1.0; // --- Integer --- case "Integer": return _isInt(value); case "Int32": return _isInt(value) && value <= 0x7fffffff && value >= -0x80000000; case "Int16": return _isInt(value) && value <= 0x7fff && value >= -0x8000; case "Int8": return _isInt(value) && value <= 0x7f && value >= -0x80; case "Uint32": return _isUint(value) && value <= 0xffffffff; case "Uint16": return _isUint(value) && value <= 0xffff; case "Uint8": return _isUint(value) && value <= 0xff; // --- Integer Array --- case "INT32Array": return Array.isArray(value) && value.every(function(v) { return _isInt(v) && v <= 0x7fffffff && v >= -0x80000000; }); case "INT16Array": return Array.isArray(value) && value.every(function(v) { return _isInt(v) && v <= 0x7fff && v >= -0x8000; }); case "INT8Array": return Array.isArray(value) && value.every(function(v) { return _isInt(v) && v <= 0x7f && v >= -0x80; }); case "UINT32Array": return Array.isArray(value) && value.every(function(v) { return _isUint(v) && v <= 0xffffffff; }); case "UINT16Array": return Array.isArray(value) && value.every(function(v) { return _isUint(v) && v <= 0xffff; }); case "UINT8Array": return Array.isArray(value) && value.every(function(v) { return _isUint(v) && v <= 0xff; }); // --- color --- case "AARRGGBB": case "RRGGBBAA": return _isUint(value) && value <= 0xffffffff; // Uint32 case "RRGGBB": return _isUint(value) && value <= 0xffffff; // Uint24 // --- postMessage --- case "TransferableObject": return _isArrayBuffer(value) || _isCanvasProxy(value) || _isMessagePort(value); case "TransferableObjects": case "TransferableObjectArray": return _isTransferableObjects(value); } if (value === null || value === undefined) { return false; } var constructorName = _getConstructorName(value); var baseClassName = _getBaseClassName(value); if (constructorName === type || baseClassName === type) { return true; } if (type in global) { // Is this global Class? return baseClassName === type; } // if (type in global["WebModule"]) { // Is this WebModule Class? // return baseClassName === type; // } // Valid.register(type) matching if (type in _hook) { return _hook[type](type, value); } // greedy complex type matching // // "FooIntegerIDString" in global -> false // "IntegerIDString" in global -> false // "IDString" in global -> false // "String" in global -> true // var token = _splitComplexTypeName(type); if (token.length > 1) { for (var i = 0, iz = token.length; i < iz; ++i) { var compositeTypes = token.slice(i).join(""); if (compositeTypes in global) { return _some(compositeTypes); } // if (compositeTypes in global["WebModule"]) { // return _some(compositeTypes); // } } } return false; } function _isInt(value) { return _isNumber(value) && Math.ceil(value) === value; } function _isUint(value) { return _isNumber(value) && Math.ceil(value) === value && value >= 0; } } function _splitComplexTypeName(type) { // @arg PascalCaseString - "FooIntegerIDString" // @ret StringArray - ["Foo", "Integer", "ID", "String"] var token = []; type.replace(/([A-Z]+)[a-z0-9]+/g, function(_, a) { if (a.length === 1) { // "String" -> { _: "String", a: "S" } token.push(_); } else { // "IDString" -> { _: "IDString", a: "IDS" } token.push( _.slice(0, a.length - 1) ); // "ID" token.push( _.slice(a.length - 1) ); // "String" } }); return token; } function _getBaseClassName(value) { // @arg Any // @ret String // Object.prototype.toString.call(new Error()); -> "[object Error]" // Object.prototype.toString.call(new TypeError()); -> "[object Error]" return Object.prototype.toString.call(value).split(" ")[1].slice(0, -1); // -> "Error" } function _getConstructorName(value) { // @arg Any - instance, exclude null and undefined. // @ret String // _getConstructorName(new (function Aaa() {})); -> "Aaa" return value.constructor["name"] || (value.constructor + "").split(" ")[1].split("\x28")[0]; // for IE } function _isTypedArray(value) { // @arg Any // @ret Boolean var className = _getBaseClassName(value).toLowerCase(); return TYPED_ARRAYS.some(function(typeName) { return className === typeName.toLowerCase(); }); } function _isTransferableObjects(value) { // @arg Any if (Array.isArray(value)) { return value.some(function(v) { return _isArrayBuffer(v) || _isCanvasProxy(v) || _isMessagePort(v); }); } return false; } function _isArrayBuffer(value) { if (global["ArrayBuffer"]) { return value instanceof global["ArrayBuffer"]; } return false; } function _isCanvasProxy(value) { if (global["CanvasProxy"]) { return value instanceof global["CanvasProxy"]; } return false; } function _isMessagePort(value) { if (global["MessagePort"]) { return value instanceof global["MessagePort"]; } return false; } function _isFunctionArray(value) { return value.every(function(fn) { return typeof fn === "function"; }); } function Valid_some(value, // @arg String|null|undefined - "a" candidate, // @arg Object|String - "a|b|c" ignoreCase) { // @arg Boolean = false // @ret Boolean - true -> has, false -> has not ignoreCase = ignoreCase || false; if (value === null || value === undefined) { return true; // [!] } var keys = _isString(candidate) ? candidate.split(SPLITTER) : _isObject(candidate) ? Object.keys(candidate) : []; if (ignoreCase) { value = value.toLowerCase(); } return keys.some(function(token) { if (ignoreCase) { return value === token.toLowerCase(); } return value === token; }); } function Valid_keys(object, // @arg Object|Array|null|undefined - { a: 1, b: 2 } key) { // @arg String - valid choices. "a|b" // @ret Boolean - false is unmatched object. if (object === null || object === undefined) { return true; // [!] } if (_isObject(object) || // Valid.keys({a:0,b:1}, "a|b") Array.isArray(object)) { // Valid.keys([9,9], "0|1") var list = _split(key); return Object.keys(object).every(function(objectKey) { return list.indexOf(objectKey) >= 0; }); } return false; } function Valid_values(object, // @arg Object|Array|null|undefined - { a: 1, b: 2 } value) { // @arg Array - valid choices. [1, 2] // @ret Boolean - false is unmatched object. if (object === null || object === undefined) { return true; // [!] } if (_isObject(object) || // Valid.values({a:0,b:1}, [0,1]) Array.isArray(object)) { // Valid.values([9,9], [9,9]) return Object_values(object).every(function(objectValue) { return value.indexOf(objectValue) >= 0; }); } return false; } function Valid_some(value, // @arg String|null|undefined - "a" candidate, // @arg String|Object - "a|b|c", { 1: "a", 2: "b" }, ["a", "b"] ignoreCase) { // @arg Boolean = false // @ret Boolean - true -> has, false -> has not // Valid.some("foo", "foo|bar"); -> true // Valid.some("foo", { foo:1, bar: 2 }); -> true ignoreCase = ignoreCase || false; if (value === null || value === undefined) { return true; // [!] } var keys = _isString(candidate) ? candidate.split(SPLITTER) : _isObject(candidate) ? Object.keys(candidate) : []; if (ignoreCase) { value = value.toLowerCase(); } return keys.some(function(token) { if (ignoreCase) { return value === token.toLowerCase(); } return value === token; }); } function Valid_json(json, // @arg JSONObject scheme) { // @arg JSONObject // @ret Boolean - false is invalid. var rv = _json(json, scheme, ""); if (rv) { return true; } console.log("json: " + JSON.stringify(json, null, 2)); console.log("scheme: " + JSON.stringify(scheme, null, 2)); return false; } function _json(json, scheme, path) { path = path || ""; return Object.keys(scheme).every(function(schemeKey) { var schemeType = Object.prototype.toString.call(scheme[schemeKey]).slice(8, -1); if (schemeKey in json) { if ( !Valid_type(json[schemeKey], schemeType) ) { console.error("Valid.json type missmatch: " + path + schemeKey + " is not " + schemeType); return false; } else if (schemeType === "Object" || schemeType === "Array") { return _json(json[schemeKey], scheme[schemeKey], path + schemeKey + "."); } return true; } console.error("Valid.json unknown property: " + path + schemeKey); return false; }); } function Valid_stack(message, // @arg String = "" depth) { // @arg Integer = 3 depth = depth || 3; var rv = ""; try { throw new Error(); } catch (o_o) { rv = (message || "") + "\n" + o_o.stack.split("\n").slice(depth).join("\n"); } return rv; } function Valid_register(type, // @arg HookTypeString callback) { // @arg Function - callback(type, value):Boolean _hook[type] = callback; } function Valid_unregister(type) { // @arg HookTypeString delete _hook[type]; } function Valid_isRegistered(type) { // @arg HookTypeString // @ret Boolean return type in _hook; } function _isObject(object) { // @arg Object|Any // @ret Boolean return object.constructor === ({}).constructor; } function _isNumber(object) { // @arg Number|Any // @ret Boolean return typeof object === "number"; } function _isString(object) { // @arg String|Any // @ret Boolean return typeof object === "string"; } function _split(keywords) { // @arg String return keywords.replace(/ /g, "").split(SPLITTER); } // ES2016 function. copy from ES.js function Object_values(source) { // @arg Object|Function|Array // @ret ValueAnyArray [key, ... ] var keys = Object.keys(source); var i = 0, iz = keys.length; var result = new Array(iz); for (; i < iz; ++i) { result[i] = source[keys[i]]; } return result; } // --- exports --------------------------------------------- if (typeof module !== "undefined") { module["exports"] = Valid; } global["Valid"] = Valid; })(GLOBAL); // Help.js (function(global) { "use strict"; // --- dependency modules ---------------------------------- var Reflection = global["Reflection"]; var Console = global["Console"]; // --- define / local variables ---------------------------- // --- class / interfaces ---------------------------------- function Help(target, // @arg Function|String - function or function-path or search keyword. highlight, // @arg String = "" - code highlight. options) { // @arg Object = {} - { nolink } // @options.nolink Boolean = false // @desc quick online help. _if(!/string|function/.test(typeof target), Help, "target"); _if(!/string|undefined/.test(typeof highlight), Help, "highlight"); options = options || {}; var resolved = Reflection["resolve"](target); var search = Reflection["getSearchLink"](resolved["path"]); var reference = Reflection["getReferenceLink"](resolved["path"]); var fn = resolved["fn"]; var code = ""; switch (typeof fn) { case "function": code = fn + ""; break; case "object": code = JSON.stringify(fn, null, 2); } _syntaxHighlight(code, highlight); if (!options.noLink) { Console["link"](search["url"], search["title"]); if (reference) { Console["link"](reference["url"], reference["title"]); } } } Help["repository"] = "https://github.com/uupaa/Help.js"; _defineGetter(); // --- implements ------------------------------------------ function _syntaxHighlight(code, // @arg String hint) { // @arg String = "" if ( Console["isEnabledStyle"]() ) { console.log.apply(console, Reflection["syntaxHighlight"](code, hint)); } else { console.log(code); } } function _defineGetter() { Object.defineProperty(Function["prototype"], "help", { get: function() { Help(this); }, configurable: true }); Object.defineProperty(String["prototype"], "help", { get: function() { Help(this); }, configurable: true }); } /* function _deleteGetter() { delete Function.prototype.help; delete String.prototype.help; } */ // --- validate / assertions ------------------------------- //{@dev function _if(value, fn, hint) { if (value) { throw new Error(fn.name + " " + hint); } } //}@dev // --- exports --------------------------------------------- if (typeof module !== "undefined") { module["exports"] = Help; } global["Help"] = Help; })(GLOBAL); // Task.js (function(global) { "use strict"; // --- dependency modules ---------------------------------- // --- define / local variables ---------------------------- var _taskInstances = {}; // instances. { "taskName@counter": TaskInstance, ... } var _taskNumber = 0; function NOP() {} // --- class / interfaces ---------------------------------- function Task(taskCount, // @arg Integer - user task count, value from 1. callback, // @arg Function|Task = null - callback(err:Error, buffer:Array) options) { // @arg Object = {} - { tick, name, buffer } // @options.tick Function = null - tick(taskName) callback. // @options.name String = "anonymous" - task name. // @options.buffer Array = [] - buffer. // @desc Counter based task executor. options = options || {}; callback = callback || NOP; var junction = callback instanceof Task; var tick = options["tick"] || null; var name = options["name"] || "anonymous"; var buffer = options["buffer"] || (junction ? callback["buffer"]() : []); // Junction -> Buffer share this["name"] = name + "@" + (++_taskNumber); // String: "task@1" this._ = { tick: tick, // Function: buffer: buffer, // Array: callback: callback, // Function|Task: finished callback. junction: junction, // Boolean: callback is Junction. taskCount: taskCount, // Number: user task count. missableCount: 0, // Integer: number of missable count. passedCount: 0, // Integer: Task#pass() called count. missedCount: 0, // Integer: Task#miss() called count. message: "", // String: new Error(message) state: "" // String: current state. ""(progress), "pass", "miss", "exit" }; _taskInstances[this["name"]] = this; // register task instance. if (!taskCount) { _update(this, "init"); // user task count is zero -> finished. } } Task["prototype"] = { "constructor": Task, // new Task(tackCount:Integer, callback:Function|Task = null, options:Object = {}) // --- buffer accessor --- "pop": Task_pop, // Task#pop():Any|undefined "push": Task_push, // Task#push(value:Any):this "shift": Task_shift, // Task#shift():Any|undefined "unshift": Task_unshift, // Task#unshift(value:Any):this "set": Task_set, // Task#set(key:String, value:Any):this // --- flow state --- "done": Task_done, // Task#done(err:Error|null):this "pass": Task_pass, // Task#pass():this "miss": Task_miss, // Task#miss():this "exit": Task_exit, // Task#exit():this // --- closure function --- "passfn": Task_passfn, // Task#passfn():TaskPassClosureFunction "missfn": Task_missfn, // Task#missfn():TaskMissClosureFunction // --- utility --- "state": Task_state, // Task#state():String "buffer": Task_buffer, // Task#buffer():Array|null "extend": Task_extend, // Task#extend(count:Integer):this "message": Task_message, // Task#message(message:Error|String):this "missable": Task_missable, // Task#missable(count:Integer):this "isFinished": Task_isFinished // Task#isFinished():Boolean }; Task["dump"] = Task_dump; // Task.dump(filter:String = ""):Object Task["clear"] = Task_clear; // Task.clear():void Task["drop"] = Task_clear; // [DEPRECATED] Task.drop():void Task["flatten"] = Task_flatten; // Task.flatten(source:Array):Array Task["arraynize"] = Task_arraynize; // Task.arraynize(source:Array):Array Task["objectize"] = Task_objectize; // Task.objectize(source:Array):Object // --- task runner --- Task["run"] = Task_run; // Task.run(taskPlan:String, // taskMap:TaskMapObject|TaskMapArray, // callback:Function|Task = null, // options:Object = {}):Task Task["loop"] = Task_loop; // Task.loop(source:Object|Array, // tick:Function, // callback:Function|Task = null, // options:Object = {}):Task // --- implements ------------------------------------------ function Task_pop() { // @ret Any|undefined if (this._.buffer) { return this._.buffer.pop(); } return this; } function Task_push(value) { // @arg Any // @ret this if (this._.buffer) { this._.buffer.push(value); } return this; } function Task_shift() { // @ret Any|undefined if (this._.buffer) { return this._.buffer.shift(); } return this; } function Task_unshift(value) { // @arg Any // @ret this if