├── .github ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── BASE_MODEL ├── .eslintignore ├── .eslintrc ├── .files.json ├── .gitignore ├── .npmignore ├── .travis.yml ├── README.md ├── alt │ └── REPOSITORY_NAME.ts ├── bin │ └── REPOSITORY_NAME.js ├── index.js ├── lib │ ├── REPOSITORY_NAME.js │ ├── SUB_CLASS.js │ └── WebModule.js ├── lint │ └── plato │ │ └── README.md ├── package.json ├── release │ └── README.md └── test │ ├── browser │ ├── index.html │ ├── template │ │ ├── index.html │ │ └── worker.js │ └── worker.js │ ├── el │ ├── index.html │ ├── main.js │ ├── package.json │ └── template │ │ └── index.html │ ├── node │ ├── index.js │ └── template │ │ └── index.js │ ├── nw │ ├── index.html │ ├── package.json │ └── template │ │ └── index.html │ └── testcase.js ├── LICENSE ├── README.md ├── lib ├── Console.js ├── Help.js ├── ModuleSystem.js ├── Reflection.js ├── Task.js ├── Test.js └── Valid.js ├── package.json └── run ├── add-src.js ├── add-subclass.js ├── es6to5.js ├── minify.js ├── page.js ├── patch.js ├── score.js ├── setup.js ├── sim.js ├── sync.js ├── watch.js └── wiki.js /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTOR LICENSE AGREEMENT 2 | -------------------------------------------------------------------------------- /.github/CONTRIBUTORS.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uupaa/WebModule/fb1c867913c9fb769737264770eed688286303b0/.github/CONTRIBUTORS.md -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uupaa/WebModule/fb1c867913c9fb769737264770eed688286303b0/.github/ISSUE_TEMPLATE.md -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uupaa/WebModule/fb1c867913c9fb769737264770eed688286303b0/.github/PULL_REQUEST_TEMPLATE.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## ignore the dependency modules directory 2 | node_modules 3 | 4 | ## ignore the file that is automatically regenerated 5 | lint/plato/assets 6 | lint/plato/files 7 | lint/plato/*.html 8 | .Minify* 9 | release/*.min.js 10 | #test/index.html 11 | #test/node.js 12 | #test/nw.html 13 | #test/package.json 14 | #test/wmtools.js 15 | #test/worker.js 16 | 17 | ## ignore the setting files 18 | .DS_Store 19 | 20 | ## dust 21 | lib/*.min.js 22 | npm-debug.log 23 | 24 | ## ignore gh-pages dir 25 | ## $ git-new-workdir . gh-pages gh-pages 26 | gh-pages 27 | 28 | -------------------------------------------------------------------------------- /BASE_MODEL/.eslintignore: -------------------------------------------------------------------------------- 1 | # lib/WebModule.js 2 | 3 | -------------------------------------------------------------------------------- /BASE_MODEL/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "node": true 5 | }, 6 | "globals": { 7 | "modules": false, 8 | "BENCHMARK": false, 9 | "IN_EL": false, 10 | "IN_BROWSER": false, 11 | "IN_WORKER": false, 12 | "IN_NODE": false, 13 | "IN_NW": false, 14 | "$type": false, 15 | "$keys": false, 16 | "$some": false, 17 | "$args": false, 18 | "$valid": false, 19 | "unescape": false, 20 | "escape": false 21 | }, 22 | "rules": { 23 | "strict": [0], 24 | "new-cap": [0], 25 | "no-shadow": [0], 26 | "camelcase": [0], 27 | "key-spacing": [0], 28 | "dot-notation": [0], 29 | "comma-dangle": [0], 30 | "no-multi-spaces": [0], 31 | "no-unused-vars": [1, { "vars": "all", "args": "after-used"} ], 32 | "no-underscore-dangle": [0], 33 | "no-use-before-define": [0] 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /BASE_MODEL/.files.json: -------------------------------------------------------------------------------- 1 | { 2 | "alt": { 3 | "REPOSITORY_NAME.ts": ["scan"] 4 | }, 5 | "bin": { 6 | "REPOSITORY_NAME.js": ["scan"] 7 | }, 8 | "lib": { 9 | "WebModule.js": ["scan"], 10 | "REPOSITORY_NAME.js": ["scan"] 11 | }, 12 | "lint": { 13 | "plato": { 14 | "README.md": [] 15 | } 16 | }, 17 | "release": { 18 | "README.md": [] 19 | }, 20 | "test": { 21 | "testcase.js": ["scan"], 22 | "browser": { 23 | "template": { 24 | "index.html": ["scan"], 25 | "worker.js": ["scan"] 26 | }, 27 | "index.html": [], 28 | "worker.js": [] 29 | }, 30 | "node": { 31 | "template": { 32 | "index.js": ["scan"] 33 | }, 34 | "index.js": [] 35 | }, 36 | "nw": { 37 | "template": { 38 | "index.html": ["scan"] 39 | }, 40 | "index.html": [], 41 | "package.json": [] 42 | }, 43 | "el": { 44 | "template": { 45 | "index.html": ["scan"] 46 | }, 47 | "index.html": [], 48 | "main.js": [], 49 | "package.json": [] 50 | } 51 | }, 52 | ".gitignore": [], 53 | ".eslintrc": [], 54 | ".eslintignore": [], 55 | ".npmignore": [], 56 | ".travis.yml": ["scan"], 57 | "index.js": ["scan"], 58 | "package.json": ["scan"], 59 | "README.md": ["scan"] 60 | } 61 | 62 | -------------------------------------------------------------------------------- /BASE_MODEL/.gitignore: -------------------------------------------------------------------------------- 1 | ## ignore the dependency modules directory 2 | node_modules 3 | 4 | ## ignore the file that is automatically regenerated 5 | lint/plato/assets 6 | lint/plato/files 7 | lint/plato/*.html 8 | .Minify* 9 | release/*.min.js 10 | #test/index.html 11 | #test/node.js 12 | #test/nw.html 13 | #test/package.json 14 | #test/wmtools.js 15 | #test/worker.js 16 | 17 | ## ignore the setting files 18 | .DS_Store 19 | 20 | ## dust 21 | lib/*.min.js 22 | npm-debug.log 23 | 24 | ## ignore gh-pages dir 25 | ## $ git-new-workdir . gh-pages gh-pages 26 | gh-pages 27 | 28 | -------------------------------------------------------------------------------- /BASE_MODEL/.npmignore: -------------------------------------------------------------------------------- 1 | ## ignore the dependency modules directory 2 | node_modules 3 | 4 | ## ignore the file that is automatically regenerated 5 | lint/plato/assets 6 | lint/plato/files 7 | lint/plato/*.html 8 | .Minify* 9 | release/*.min.js 10 | #test/index.html 11 | #test/node.js 12 | #test/nw.html 13 | #test/package.json 14 | #test/wmtools.js 15 | #test/worker.js 16 | 17 | ## ignore the setting files 18 | .DS_Store 19 | .vimrc* 20 | .git* 21 | 22 | ## dust 23 | lib/*.min.js 24 | npm-debug.log 25 | 26 | -------------------------------------------------------------------------------- /BASE_MODEL/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4.1.2" 4 | # http://docs.travis-ci.com/user/workers/container-based-infrastructure/ 5 | sudo: false 6 | cache: 7 | directories: 8 | - node_modules 9 | before_script: 10 | - "pwd" 11 | - "cd .." 12 | - "git clone https://github.com/uupaa/WebModule.git" 13 | - "cd -" 14 | - "npm install" 15 | - "npm install uupaa.closurecompiler.js" 16 | - "node node_modules/uupaa.closurecompiler.js --package" 17 | script: 18 | - "npm run node" 19 | 20 | -------------------------------------------------------------------------------- /BASE_MODEL/README.md: -------------------------------------------------------------------------------- 1 | # <> [![Build Status](https://travis-ci.org/<>/<>.svg)](https://travis-ci.org/<>/<>) 2 | 3 | [![npm](https://nodei.co/npm/<>.<>.svg?downloads=true&stars=true)](https://nodei.co/npm/<>.<>/) 4 | 5 | <> 6 | 7 | This module made of [WebModule](https://github.com/uupaa/WebModule). 8 | 9 | ## Documentation 10 | - [Overview](https://github.com/<>/<>/wiki/) 11 | - [API Spec](https://github.com/<>/<>/wiki/<>) 12 | 13 | ## Browser, NW.js and Electron 14 | 15 | ```js 16 | 17 | 18 | 21 | ``` 22 | 23 | ## WebWorkers 24 | 25 | ```js 26 | importScripts("/lib/WebModule.js"); 27 | importScripts("/lib/<>"); 28 | 29 | ``` 30 | 31 | ## Node.js 32 | 33 | ```js 34 | require("/lib/WebModule.js"); 35 | require("/lib/<>"); 36 | 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /BASE_MODEL/alt/REPOSITORY_NAME.ts: -------------------------------------------------------------------------------- 1 | export class <> { 2 | static name = "<>"; 3 | static repository = "https://github.com/<>/<>.js"; 4 | 5 | _value: number; 6 | 7 | constructor(value:number) { 8 | this._value = value; 9 | } 10 | value():number { 11 | return this._value; 12 | } 13 | isNumber():boolean { 14 | return typeof this._value === "number"; 15 | } 16 | isInteger():boolean { 17 | return typeof this._value === "number" && 18 | Math.ceil(this._value) === this._value; 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /BASE_MODEL/bin/REPOSITORY_NAME.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | (function(global) { 4 | 5 | var USAGE = _multiline(function() {/* 6 | Usage: 7 | node bin/<>.js [-h or --help] 8 | [-v or --verbose] 9 | [--output output-file] 10 | input-file [input-file ...] 11 | 12 | See: 13 | https://github.com/<>/<>/wiki/<> 14 | */}); 15 | 16 | 17 | var CONSOLE_COLOR = { 18 | RED: "\u001b[31m", 19 | YELLOW: "\u001b[33m", 20 | GREEN: "\u001b[32m", 21 | CLEAR: "\u001b[0m" 22 | }; 23 | 24 | var <> = require("../lib/<>"); 25 | var fs = require("fs"); 26 | var cp = require("child_process"); 27 | var wmlib = process.argv[1].split("/").slice(0, -2).join("/") + "/lib/"; // "WebModule/lib/" 28 | var Task = require(wmlib + "Task.js"); 29 | var argv = process.argv.slice(2); 30 | var options = _parseCommandLineOptions({ 31 | help: false, // Boolean: show help. 32 | verbose: false, // Boolean: verbose mode. 33 | output: "a.out", // String: output file. 34 | inputs: [] // StringArray: input files. [file, ...] 35 | }); 36 | 37 | if (options.help) { 38 | console.log(CONSOLE_COLOR.YELLOW + USAGE + CONSOLE_COLOR.CLEAR); 39 | return; 40 | } 41 | 42 | if (options.verbose) { 43 | } 44 | 45 | /* 46 | <>({ 47 | "verbose": options.verbose, 48 | "output": options.output, 49 | "inputs": options.inputs, 50 | }, function(err) { 51 | // 52 | }); 53 | */ 54 | 55 | function _parseCommandLineOptions(options) { // @arg Object: 56 | // @ret Object: 57 | for (var i = 0, iz = argv.length; i < iz; ++i) { 58 | switch (argv[i]) { 59 | case "-h": 60 | case "--help": options.help = true; break; 61 | case "-v": 62 | case "--verbose": options.verbose = true; break; 63 | case "--output": options.output = argv[++i]; break; 64 | default: 65 | var file = argv[i]; 66 | if (options.inputs.indexOf(file) < 0) { // avoid duplicate 67 | options.inputs.push(file); 68 | } 69 | } 70 | } 71 | return options; 72 | } 73 | 74 | function _multiline(fn) { // @arg Function: 75 | // @ret String: 76 | return (fn + "").split("\n").slice(1, -1).join("\n"); 77 | } 78 | 79 | })(GLOBAL); 80 | 81 | -------------------------------------------------------------------------------- /BASE_MODEL/index.js: -------------------------------------------------------------------------------- 1 | //module.exports = require("./bin/<>"); 2 | module.exports = require("./lib/<>"); 3 | 4 | -------------------------------------------------------------------------------- /BASE_MODEL/lib/REPOSITORY_NAME.js: -------------------------------------------------------------------------------- 1 | (function moduleExporter(name, closure) { 2 | "use strict"; 3 | 4 | var entity = GLOBAL["WebModule"]["exports"](name, closure); 5 | 6 | if (typeof module !== "undefined") { 7 | module["exports"] = entity; 8 | } 9 | return entity; 10 | 11 | })("<>", function moduleClosure(global, WebModule, VERIFY, VERBOSE) { 12 | "use strict"; 13 | 14 | // --- technical terms / data structure -------------------- 15 | // --- dependency modules ---------------------------------- 16 | // --- import / local extract functions -------------------- 17 | // --- define / local variables ---------------------------- 18 | // --- class / interfaces ---------------------------------- 19 | function <>() { 20 | this._value = ""; 21 | } 22 | 23 | <>["repository"] = "https://github.com/<>/<>.js"; 24 | <>["prototype"] = Object.create(<>, { 25 | "constructor": { 26 | "value": <> // new <>():<> 27 | }, 28 | // --- methods --- 29 | "method": { 30 | "value": <>_method // <>#method(a:String, b:String):String 31 | }, 32 | // --- accessor --- 33 | "value": { 34 | "set": function(v) { this._value = v; }, 35 | "get": function() { return this._value; } 36 | }, 37 | }); 38 | 39 | // --- implements ------------------------------------------ 40 | function <>_method(a, // @arg String 41 | __19_SPACE_________ b) { // @arg String 42 | __19_SPACE_________ // @ret String - a + b 43 | //{@dev 44 | if (VERIFY) { 45 | $valid($type(a, "String"), <>_method, "a"); 46 | $valid($type(b, "String"), <>_method, "b"); 47 | } 48 | //}@dev 49 | 50 | return a + b; 51 | } 52 | 53 | return <>; // return entity 54 | 55 | }); 56 | 57 | -------------------------------------------------------------------------------- /BASE_MODEL/lib/SUB_CLASS.js: -------------------------------------------------------------------------------- 1 | (function moduleExporter(name, closure) { 2 | "use strict"; 3 | 4 | var entity = GLOBAL["WebModule"]["exports"](name, closure); 5 | 6 | if (typeof module !== "undefined") { 7 | module["exports"] = entity; 8 | } 9 | return entity; 10 | 11 | })("<>", function moduleClosure(global, WebModule, VERIFY, VERBOSE) { 12 | "use strict"; 13 | 14 | // --- technical terms / data structure -------------------- 15 | // --- dependency modules ---------------------------------- 16 | // --- import / local extract functions -------------------- 17 | // --- define / local variables ---------------------------- 18 | var <> = WebModule["<>"]; 19 | 20 | // --- class / interfaces ---------------------------------- 21 | function <>() { 22 | <>.apply(this, arguments); // constructor chain. 23 | } 24 | 25 | <>["prototype"] = Object.create(<>.prototype, { 26 | "constructor": { 27 | "value": <> // new <>():<> 28 | }, 29 | // --- methods --- 30 | "method": { 31 | "value": <>_method // <>#method(a:String, b:String):String 32 | }, 33 | // --- accessor --- 34 | "value": { 35 | "set": function(v) { this._value = v; }, 36 | "get": function() { return this._value; } 37 | }, 38 | }); 39 | 40 | // --- implements ------------------------------------------ 41 | function <>_method(a, b) { 42 | return a + b; 43 | } 44 | 45 | return <>; // return entity 46 | 47 | }); 48 | 49 | -------------------------------------------------------------------------------- /BASE_MODEL/lib/WebModule.js: -------------------------------------------------------------------------------- 1 | // http://git.io/WebModule 2 | 3 | // --- global variables ------------------------------------ 4 | // https://github.com/uupaa/WebModule/wiki/WebModuleIdiom 5 | var GLOBAL = (this || 0).self || global; 6 | 7 | // --- environment detection ------------------------------- 8 | // https://github.com/uupaa/WebModule/wiki/EnvironmentDetection 9 | (function() { 10 | 11 | var hasGlobal = !!GLOBAL.global; // Node.js, NW.js, Electron 12 | var processType = !!(GLOBAL.process || 0).type; // Electron(render and main) 13 | var nativeTimer = !!/native/.test(setTimeout); // Node.js, Electron(main) 14 | 15 | GLOBAL.IN_BROWSER = !hasGlobal && "document" in GLOBAL; // Browser and Worker 16 | GLOBAL.IN_WORKER = !hasGlobal && "WorkerLocation" in GLOBAL; // Worker 17 | GLOBAL.IN_NODE = hasGlobal && !processType && !nativeTimer; // Node.js 18 | GLOBAL.IN_NW = hasGlobal && !processType && nativeTimer; // NW.js 19 | GLOBAL.IN_EL = hasGlobal && processType; // Electron(render and main) 20 | 21 | })(); 22 | 23 | // --- validation and assertion functions ------------------ 24 | //{@dev https://github.com/uupaa/WebModule/wiki/Validate 25 | GLOBAL.$type = function(v, types) { return GLOBAL.Valid ? GLOBAL.Valid.type(v, types) : true; }; 26 | GLOBAL.$keys = function(o, keys) { return GLOBAL.Valid ? GLOBAL.Valid.keys(o, keys) : true; }; 27 | GLOBAL.$some = function(v, cd, ig) { return GLOBAL.Valid ? GLOBAL.Valid.some(v, cd, ig) : true; }; 28 | GLOBAL.$args = function(api, args) { return GLOBAL.Valid ? GLOBAL.Valid.args(api, args) : true; }; 29 | GLOBAL.$valid = function(v, api, hl) { return GLOBAL.Valid ? GLOBAL.Valid(v, api, hl) : true; }; 30 | GLOBAL.$values = function(o, vals) { return GLOBAL.Valid ? GLOBAL.Valid.values(o, vals) : true; }; 31 | //}@dev 32 | 33 | // --- WebModule ------------------------------------------- 34 | GLOBAL.WebModule = { 35 | CODE: {}, // source code container. 36 | VERIFY: false, // verify mode flag. 37 | VERBOSE: false, // verbose mode flag. 38 | PUBLISH: false, // publish flag, module publish to global namespace. 39 | exports: function(moduleName, // @arg ModuleNameString 40 | moduleClosure) { // @arg JavaScriptCodeString 41 | // @ret ModuleObject 42 | var wm = this; // GLOBAL.WebModule 43 | 44 | // https://github.com/uupaa/WebModule/wiki/SwitchModulePattern 45 | var alias = wm[moduleName] ? (moduleName + "_") : moduleName; 46 | 47 | if (!wm[alias]) { // secondary module already exported -> skip 48 | wm[alias] = moduleClosure(GLOBAL, wm, wm.VERIFY, wm.VERBOSE); // evaluate the module entity. 49 | wm.CODE[alias] = moduleClosure + ""; // store to the container. 50 | 51 | if (wm.PUBLISH && !GLOBAL[alias]) { 52 | GLOBAL[alias] = wm[alias]; // module publish to global namespace. 53 | } 54 | } 55 | return wm[alias]; 56 | } 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /BASE_MODEL/lint/plato/README.md: -------------------------------------------------------------------------------- 1 | Place the files generated by Plato. 2 | 3 | -------------------------------------------------------------------------------- /BASE_MODEL/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<>.<>", 3 | "version": "0.0.0", 4 | "description": "<>", 5 | "url": "https://github.com/<>/<>", 6 | "keywords": ["<>", "WebModule", "Unstable"], 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/<>/<>.git" 10 | }, 11 | "scripts": { 12 | "sync": "node ../WebModule/run/sync.js; npm update; node ../WebModule/run/page.js", 13 | "wiki": "node ../WebModule/run/wiki.js", 14 | "min": "node ../WebModule/run/minify.js --verbose --strict --keep --pretty", 15 | "build": "node ../WebModule/run/minify.js --verbose --strict --keep --release", 16 | "watch": "node ../WebModule/run/watch.js --verbose --run lint", 17 | "page": "node ../WebModule/run/page.js --verbose", 18 | "test": "npm run min; npm run node; npm run browser", 19 | "node": "NODE_ENV=production NODE_PATH=lib node test/node/index.js", 20 | "noded": "NODE_ENV=production NODE_PATH=lib node --debug-brk test/node/index.js", 21 | "browser": "open http://localhost:8000/REPOSITORY_FULLNAME/test/browser/index.html", 22 | "el": "electron test/el", 23 | "nw": "nw test/nw", 24 | "add-src": "node ../WebModule/run/add-src.js", 25 | "add-subclass": "node ../WebModule/run/add-subclass.js", 26 | "sim": "node ../WebModule/run/sim.js http://localhost:8000/REPOSITORY_FULLNAME/test/browser/index.html", 27 | "simx": "node ../WebModule/run/sim.js stop", 28 | "lint": "eslint lib/*.js", 29 | "score": "node ../WebModule/run/score.js; open lint/plato/index.html", 30 | "patch": "node ../WebModule/run/patch.js", 31 | "setup": "node ../WebModule/run/setup.js", 32 | "start": "cd ../; Python -m SimpleHTTPServer 8000 &", 33 | "stop": "killall -- Python -m SimpleHTTPServer 8000; exit 0" 34 | }, 35 | "webmodule": { 36 | "develop": false, 37 | "label": ["@dev"], 38 | "browser": { 39 | "output": "release/<>.b.min.js", 40 | "source": ["lib/<>.js"] 41 | }, 42 | "worker": { 43 | "output": "release/<>.w.min.js", 44 | "source": ["lib/<>.js"] 45 | }, 46 | "node": { 47 | "output": "release/<>.n.min.js", 48 | "source": ["lib/<>.js"] 49 | }, 50 | "nw": { 51 | "output": "release/<>.nw.min.js", 52 | "source": ["lib/<>.js"] 53 | }, 54 | "el": { 55 | "output": "release/<>.el.min.js", 56 | "source": ["lib/<>.js"] 57 | } 58 | }, 59 | "dependencies": {}, 60 | "devDependencies": {}, 61 | "lib": "./lib/", 62 | "main": "./index.js", 63 | "author": "<>", 64 | "license": "MIT", 65 | "contributors": [] 66 | } 67 | -------------------------------------------------------------------------------- /BASE_MODEL/release/README.md: -------------------------------------------------------------------------------- 1 | Place the files that release build in this folder. 2 | 3 | -------------------------------------------------------------------------------- /BASE_MODEL/test/browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /BASE_MODEL/test/browser/template/index.html: -------------------------------------------------------------------------------- 1 | <<REPOSITORY_NAME>> test 2 | 3 | 4 | 5 | 6 | 11 | 12 | __MODULES__ 13 | __WMTOOLS__ 14 | __SOURCES__ 15 | __OUTPUT__ 16 | __TEST_CASE__ 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /BASE_MODEL/test/browser/template/worker.js: -------------------------------------------------------------------------------- 1 | // <> test 2 | 3 | onmessage = function(event) { 4 | self.unitTest = event.data; // { message, setting: { secondary, baseDir } } 5 | 6 | if (!self.console) { // polyfill WebWorkerConsole 7 | self.console = function() {}; 8 | self.console.dir = function() {}; 9 | self.console.log = function() {}; 10 | self.console.warn = function() {}; 11 | self.console.error = function() {}; 12 | self.console.table = function() {}; 13 | } 14 | 15 | importScripts("../../lib/WebModule.js"); 16 | 17 | WebModule.VERIFY = __WEBMODULE_VERIFY__; 18 | WebModule.VERBOSE = __WEBMODULE_VERBOSE__; 19 | WebModule.PUBLISH = __WEBMODULE_PUBLISH__; 20 | 21 | __MODULES__ 22 | __WMTOOLS__ 23 | __SOURCES__ 24 | __OUTPUT__ 25 | __TEST_CASE__ 26 | 27 | self.postMessage(self.unitTest); 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /BASE_MODEL/test/browser/worker.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /BASE_MODEL/test/el/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /BASE_MODEL/test/el/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var app = require("app"); 4 | var BrowserWindow = require("browser-window"); 5 | 6 | process.chdir("test/el"); 7 | // var cwd = process.cwd(); 8 | // console.log(cwd); 9 | 10 | // require("crash-reporter").start(); 11 | 12 | var mainWindow = null; 13 | 14 | app.on("window-all-closed", function() { 15 | if (process.platform !== "darwin") { app.quit(); } 16 | }); 17 | 18 | app.on("ready", function() { 19 | mainWindow = new BrowserWindow({ width: 800, height: 600 }); 20 | mainWindow.loadURL("file://" + __dirname + "/index.html"); 21 | // mainWindow.webContents.on("did-finish-load", function() { 22 | // mainWindow.webContents.executeJavaScript("process.chdir('" + cwd + "')"); 23 | // }); 24 | 25 | mainWindow.on("closed", function() { 26 | mainWindow = null; 27 | }); 28 | }); 29 | 30 | 31 | -------------------------------------------------------------------------------- /BASE_MODEL/test/el/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "0.0.0", 4 | "description": "test app", 5 | "dependencies": {}, 6 | "devDependencies": {}, 7 | "lib": "./lib/", 8 | "main": "./main.js" 9 | } 10 | 11 | -------------------------------------------------------------------------------- /BASE_MODEL/test/el/template/index.html: -------------------------------------------------------------------------------- 1 | <<REPOSITORY_NAME>> test 2 | 3 | 4 | 5 | 6 | 11 | 12 | __MODULES__ 13 | __WMTOOLS__ 14 | __SOURCES__ 15 | __OUTPUT__ 16 | __TEST_CASE__ 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /BASE_MODEL/test/node/index.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /BASE_MODEL/test/node/template/index.js: -------------------------------------------------------------------------------- 1 | // <> test 2 | 3 | require("../../lib/WebModule.js"); 4 | 5 | WebModule.VERIFY = __WEBMODULE_VERIFY__; 6 | WebModule.VERBOSE = __WEBMODULE_VERBOSE__; 7 | WebModule.PUBLISH = __WEBMODULE_PUBLISH__; 8 | 9 | __MODULES__ 10 | __WMTOOLS__ 11 | __SOURCES__ 12 | __OUTPUT__ 13 | __TEST_CASE__ 14 | 15 | -------------------------------------------------------------------------------- /BASE_MODEL/test/nw/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /BASE_MODEL/test/nw/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "0.0.0", 4 | "description": "test app", 5 | "dependencies": {}, 6 | "devDependencies": {}, 7 | "lib": "./lib/", 8 | "main": "./index.html" 9 | } 10 | 11 | -------------------------------------------------------------------------------- /BASE_MODEL/test/nw/template/index.html: -------------------------------------------------------------------------------- 1 | <<REPOSITORY_NAME>> test 2 | 3 | 4 | 5 | 6 | 11 | 12 | __MODULES__ 13 | __WMTOOLS__ 14 | __SOURCES__ 15 | __OUTPUT__ 16 | __TEST_CASE__ 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /BASE_MODEL/test/testcase.js: -------------------------------------------------------------------------------- 1 | var ModuleTest<> = (function(global) { 2 | 3 | var test = new Test(["<>"], { // Add the ModuleName to be tested here (if necessary). 4 | disable: false, // disable all tests. 5 | browser: true, // enable browser test. 6 | worker: true, // enable worker test. 7 | node: true, // enable node test. 8 | nw: true, // enable nw.js test. 9 | el: true, // enable electron (render process) test. 10 | button: true, // show button. 11 | both: true, // test the primary and secondary modules. 12 | ignoreError:false, // ignore error. 13 | callback: function() { 14 | }, 15 | errorback: function(error) { 16 | console.error(error.message); 17 | } 18 | }); 19 | 20 | if (IN_BROWSER || IN_NW || IN_EL || IN_WORKER || IN_NODE) { 21 | test.add([ 22 | test<>_method, 23 | test<>_accessor, 24 | ]); 25 | } 26 | if (IN_BROWSER || IN_NW || IN_EL) { 27 | test.add([ 28 | ]); 29 | } 30 | if (IN_WORKER) { 31 | test.add([ 32 | ]); 33 | } 34 | if (IN_NODE) { 35 | test.add([ 36 | ]); 37 | } 38 | 39 | // --- test cases ------------------------------------------ 40 | function test<>_method(test, pass, miss) { 41 | 42 | var result = { 43 | 0: new WebModule.<>().method("a", "b") === "ab", // true 44 | }; 45 | 46 | if ( /false/.test(JSON.stringify(result)) ) { 47 | test.done(miss()); 48 | } else { 49 | test.done(pass()); 50 | } 51 | } 52 | 53 | function test<>_accessor(test, pass, miss) { 54 | 55 | var instance = new WebModule.<>(); 56 | instance.value = "a"; // setter 57 | 58 | if (instance.value === "a") { // getter 59 | test.done(pass()); 60 | } else { 61 | test.done(miss()); 62 | } 63 | } 64 | 65 | return test.run(); 66 | 67 | })(GLOBAL); 68 | 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 uupaa.js@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebModule 2 | 3 | Generate a JavaScript based module for Mobile Web Applications. 4 | 5 | - [Document](https://github.com/uupaa/WebModule/wiki/) 6 | - [Change Log](https://github.com/uupaa/WebModule/wiki/ChangeLog) 7 | - [Module List](https://github.com/uupaa/WebModule/wiki/ModuleList) 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/Console.js: -------------------------------------------------------------------------------- 1 | // Console.js 2 | (function(global) { 3 | "use strict"; 4 | 5 | // --- dependency modules ---------------------------------- 6 | // --- define / local variables ---------------------------- 7 | var CONSOLE_COLORS = { 8 | BLACK: "\u001b[30m", 9 | RED: "\u001b[31m", 10 | GREEN: "\u001b[32m", 11 | YELLOW: "\u001b[33m", 12 | BLUE: "\u001b[34m", 13 | MAGENTA:"\u001b[35m", 14 | CYAN: "\u001b[36m", 15 | WHITE: "\u001b[37m", 16 | CLEAR: "\u001b[0m" 17 | }; 18 | 19 | // --- class / interfaces ---------------------------------- 20 | var Console = { 21 | "log": Console_log, // Console.log(...:Any):void 22 | "warn": Console_warn, // Console.warn(...:Any):void 23 | "error": Console_error, // Console.error(...:Any):void 24 | "color": Console_color, // Console.color(color:ColorString, message:String):void 25 | "link": Console_link, // Console.link(url:String, title:String = "", style:Object = null):void 26 | "isEnabledStyle": Console_isEnabledStyle, // Console.isEnabledStyle():Boolean 27 | }; 28 | 29 | // --- implements ------------------------------------------ 30 | function Console_log() { 31 | console.log.apply(console, arguments); 32 | } 33 | 34 | function Console_warn() { 35 | console.warn.apply(console, arguments); 36 | } 37 | 38 | function Console_error() { 39 | console.error.apply(console, arguments); 40 | } 41 | 42 | function Console_color(color, // @arg ColorString 43 | message) { // @arg String 44 | if ( Console_isEnabledStyle() ) { 45 | color = color.toUpperCase(); 46 | if (color in CONSOLE_COLORS) { 47 | console.log("%c" + message, "color:" + color, ""); 48 | } 49 | } else if (IN_NODE) { 50 | color = color.toUpperCase(); 51 | if (color in CONSOLE_COLORS) { 52 | console.log(CONSOLE_COLORS[color] + message + CONSOLE_COLORS.CLEAR); 53 | } 54 | } else { 55 | console.log(message); 56 | } 57 | } 58 | 59 | function Console_link(url, // @arg URLString 60 | title, // @arg String = "" 61 | style) { // @arg Object - { link, mark } 62 | // @style.link String = "border-bottom:2px solid #9ff" 63 | // @style.mark String = "▶" 64 | title = title || ""; 65 | style = style || {}; 66 | 67 | var linkStyle = style["link"] || "border-bottom:2px solid #9ff"; 68 | var mark = style["mark"] || "\u25b6"; 69 | 70 | if ( Console_isEnabledStyle() ) { 71 | console.log.apply( console, _stylishLink(url, title, linkStyle, mark) ); 72 | } else { 73 | console.log(title + url); 74 | } 75 | } 76 | 77 | function _stylishLink(url, title, linkStyle, mark) { 78 | if (!/%/.test(url)) { 79 | var link = ""; 80 | 81 | if (title) { 82 | link = mark + " " + title + "\n %c" + url + "%c"; 83 | } else { 84 | link = "%c" + url + "%c"; 85 | } 86 | return [link].concat([linkStyle, ""]); 87 | } 88 | return [title, url]; 89 | } 90 | 91 | function Console_isEnabledStyle() { // @ret Boolean 92 | if (global["navigator"]) { 93 | if ( /Chrome/.test( global["navigator"]["userAgent"] || "" ) ) { 94 | if (IN_BROWSER) { 95 | return true; 96 | } 97 | } 98 | } 99 | return false; 100 | } 101 | 102 | if (console && !console.table) { 103 | console.table = console.dir; 104 | } 105 | 106 | // --- exports --------------------------------------------- 107 | if (typeof module !== "undefined") { 108 | module["exports"] = Console; 109 | } 110 | global["Console"] = Console; 111 | 112 | })(GLOBAL); 113 | 114 | -------------------------------------------------------------------------------- /lib/Help.js: -------------------------------------------------------------------------------- 1 | // Help.js 2 | (function(global) { 3 | "use strict"; 4 | 5 | // --- dependency modules ---------------------------------- 6 | var Reflection = global["Reflection"]; 7 | var Console = global["Console"]; 8 | 9 | // --- define / local variables ---------------------------- 10 | // --- class / interfaces ---------------------------------- 11 | function Help(target, // @arg Function|String - function or function-path or search keyword. 12 | highlight, // @arg String = "" - code highlight. 13 | options) { // @arg Object = {} - { nolink } 14 | // @options.nolink Boolean = false 15 | // @desc quick online help. 16 | if (typeof target === "object" && target["repository"]) { 17 | // var Class = { function, ... } object 18 | console.info(target); 19 | return; 20 | } 21 | _if(!/string|function/.test(typeof target), Help, "target"); 22 | _if(!/string|undefined/.test(typeof highlight), Help, "highlight"); 23 | options = options || {}; 24 | 25 | var resolved = Reflection["resolve"](target); 26 | var search = Reflection["getSearchLink"](resolved["path"]); 27 | var reference = Reflection["getReferenceLink"](resolved["path"]); 28 | 29 | var fn = resolved["fn"]; 30 | var code = ""; 31 | 32 | switch (typeof fn) { 33 | case "function": code = fn + ""; break; 34 | case "object": code = JSON.stringify(fn, null, 2); 35 | } 36 | _syntaxHighlight(code, highlight); 37 | if (!options.noLink) { 38 | Console["link"](search["url"], search["title"]); 39 | if (reference) { 40 | Console["link"](reference["url"], reference["title"]); 41 | } 42 | } 43 | } 44 | 45 | Help["repository"] = "https://github.com/uupaa/Help.js"; 46 | 47 | _defineGetter(); 48 | 49 | // --- implements ------------------------------------------ 50 | function _syntaxHighlight(code, // @arg String 51 | hint) { // @arg String = "" 52 | if ( Console["isEnabledStyle"]() ) { 53 | console.log.apply(console, Reflection["syntaxHighlight"](code, hint)); 54 | } else { 55 | console.log(code); 56 | } 57 | } 58 | 59 | function _defineGetter() { 60 | Object.defineProperty(Function["prototype"], "help", { 61 | get: function() { Help(this); }, 62 | configurable: true 63 | }); 64 | Object.defineProperty(String["prototype"], "help", { 65 | get: function() { Help(this); }, 66 | configurable: true 67 | }); 68 | } 69 | 70 | /* 71 | function _deleteGetter() { 72 | delete Function.prototype.help; 73 | delete String.prototype.help; 74 | } 75 | */ 76 | 77 | // --- validate / assertions ------------------------------- 78 | //{@dev 79 | function _if(value, fn, hint) { 80 | if (value) { 81 | throw new Error(fn.name + " " + hint); 82 | } 83 | } 84 | //}@dev 85 | 86 | // --- exports --------------------------------------------- 87 | if (typeof module !== "undefined") { 88 | module["exports"] = Help; 89 | } 90 | global["Help"] = Help; 91 | 92 | })(GLOBAL); 93 | 94 | 95 | -------------------------------------------------------------------------------- /lib/ModuleSystem.js: -------------------------------------------------------------------------------- 1 | // Module.js 2 | (function(global) { 3 | "use strict"; 4 | 5 | // --- dependency modules ---------------------------------- 6 | var fs = require("fs"); 7 | 8 | // --- define / local variables ---------------------------- 9 | // --- class / interfaces ---------------------------------- 10 | var ModuleSystem = { 11 | getDependencies: ModuleSystem_getDependencies, 12 | collectPackageFiles: ModuleSystem_collectPackageFiles, 13 | sortModuleListByDependencyOrder: 14 | ModuleSystem_sortModuleListByDependencyOrder, 15 | getFileList: ModuleSystem_getFileList, 16 | toUniqueArray: ModuleSystem_toUniqueArray, 17 | collectBuildTarget: ModuleSystem_collectBuildTarget, 18 | upgradePackageJSON: ModuleSystem_upgradePackageJSON, // ModuleSystem.upgradePackageJSON(pkg:JSONObject):JSONObject 19 | prettyPrint: ModuleSystem_prettyPrint // ModuleSystem.prettyPrint(str:JSONString):JSONString 20 | }; 21 | 22 | // --- implements ------------------------------------------ 23 | function ModuleSystem_getDependencies(releaseBuild) { // @arg Boolean = false 24 | // @ret Object - { nw:PathStringArray, el:PathStringArray, node:PathStringArray, worker:PathStringArray, browser:PathStringArray, label:StringArray } 25 | releaseBuild = releaseBuild || false; 26 | 27 | var packages = {}; // cached package.json { module: JSON.parse("package.json"), ...} 28 | var tree = {}; // dependency tree { "module1": { "module2": { ... }, ... } }; 29 | var modules = []; // [module, ...] 30 | 31 | ModuleSystem_collectPackageFiles(packages, tree, modules, releaseBuild); 32 | ModuleSystem_sortModuleListByDependencyOrder(tree, modules); 33 | 34 | var files = ModuleSystem_getFileList(packages, tree, modules, releaseBuild); // { nw, el, node, worker, browser, label } 35 | 36 | return { "packages": packages, "tree": tree, "modules": modules, "files": files }; 37 | } 38 | 39 | function ModuleSystem_collectPackageFiles(packages, tree, modules, releaseBuild) { 40 | _recursiveCollectPackageFiles("", packages, tree, modules, 0); 41 | 42 | function _recursiveCollectPackageFiles(dir, packages, tree, modules, nest) { 43 | var path = dir + "package.json"; 44 | 45 | if ( fs["existsSync"](path) ) { 46 | var orgpkg = JSON.parse( fs["readFileSync"](path, "UTF-8") ); 47 | 48 | var pkg = ModuleSystem_upgradePackageJSON(orgpkg); 49 | 50 | if (JSON.stringify(pkg) !== JSON.stringify(orgpkg)) { 51 | fs["writeFileSync"](path, ModuleSystem_prettyPrint(JSON.stringify(pkg, null, 2))); 52 | console.log(" upgrade " + path); 53 | } 54 | if ("webmodule" in pkg) { // has webmodule property 55 | if ( !(pkg["name"] in packages) ) { 56 | packages[pkg["name"]] = { 57 | "dir": dir, 58 | "webmodule": pkg["webmodule"], 59 | "dependencies": pkg["dependencies"], 60 | "devDependencies": pkg["devDependencies"] 61 | }; 62 | } 63 | // devDependencies の情報を収集するのは、最初の階層(nest === 0)のみ 64 | // releaseBuild が true の場合も収集しない 65 | if (nest === 0 && releaseBuild === false) { 66 | Object.keys(pkg["devDependencies"]).forEach(_drillDown); 67 | } 68 | Object.keys(pkg["dependencies"]).forEach(_drillDown); 69 | } 70 | } 71 | 72 | function _drillDown(module) { 73 | if (modules.indexOf(module) < 0) { 74 | modules.push(module); 75 | } 76 | tree[module] = {}; 77 | _recursiveCollectPackageFiles(dir + "node_modules/" + module + "/", 78 | packages, tree[module], modules, nest + 1); 79 | } 80 | } 81 | } 82 | 83 | function ModuleSystem_sortModuleListByDependencyOrder(tree, modules) { 84 | // https://gist.github.com/uupaa/ad495d35af90a4859e2c 85 | var pathList = _makePathList([], "", tree); 86 | 87 | for (var i = 0, iz = pathList.length; i < iz; ++i) { 88 | var path = pathList[i]; 89 | var array = path.split("/").slice(1); // "/a/b" -> ["a", "b"] 90 | 91 | for (var j = 0, jz = array.length - 1; j < jz; ++j) { 92 | var moduleA = array[j]; 93 | var moduleB = array[j + 1]; 94 | var posA = modules.indexOf(moduleA); 95 | var posB = modules.indexOf(moduleB); 96 | 97 | if (posA >= 0 && posB >= 0) { 98 | if (posA < posB) { // moduleA need moduleB. 99 | // move the mobuleB to before mobuleA. 100 | modules.splice(posB, 1); // Remove the moduleB, 101 | modules.splice(posA, 0, moduleB); // and injecting it to before moduleA. 102 | } 103 | } 104 | } 105 | } 106 | } 107 | 108 | function _makePathList(result, dir, subtree) { 109 | for (var key in subtree) { 110 | var path = dir + "/" + key; 111 | 112 | result.push(path); 113 | _makePathList(result, path, subtree[key]); 114 | } 115 | return result; 116 | } 117 | 118 | function ModuleSystem_getFileList(packages, 119 | tree, 120 | modules, 121 | releaseBuild) { // @ret Object - { nw, el, node, worker, browser, label } 122 | // @return.nw PathStringArray - NW.js files. 123 | // @return.el PathStringArray - Electron files. 124 | // @return.node PathStringArray - Node.js files. 125 | // @return.worker PathStringArray - Worker files. 126 | // @return.browser PathStringArray - Browser files. 127 | // @return.label StringArray - label. 128 | var nw = [], el = [], node = [], worker = [], browser = [], label = []; 129 | 130 | modules.forEach(function(name) { 131 | if (name in packages) { 132 | var config = packages[name]["webmodule"]; 133 | 134 | if (config) { 135 | if (releaseBuild && config["develop"]) { // skip 136 | return; 137 | } 138 | var dir = packages[name]["dir"]; 139 | 140 | if (1) { // [DEPRECATED FORMAT] 141 | var target = config["target"]; 142 | if (target) { 143 | console.log(name + " package.json is deprecated format. you need do `npm run sync` command"); 144 | } 145 | } 146 | 147 | // collect labels. 148 | Array.prototype.push.apply(label, config["label"]); 149 | 150 | if ("browser" in config) { 151 | config["browser"]["source"].forEach(function(file) { 152 | var path = dir + file; 153 | if (browser.indexOf(path) < 0) { browser.push(path); } 154 | }); 155 | } 156 | if ("worker" in config) { 157 | config["worker"]["source"].forEach(function(file) { 158 | var path = dir + file; 159 | if (worker.indexOf(path) < 0) { worker.push(path); } 160 | }); 161 | } 162 | if ("node" in config) { 163 | config["node"]["source"].forEach(function(file) { 164 | var path = dir + file; 165 | if (node.indexOf(path) < 0) { node.push(path); } 166 | }); 167 | } 168 | if ("nw" in config) { 169 | config["nw"]["source"].forEach(function(file) { 170 | var path = dir + file; 171 | if (nw.indexOf(path) < 0) { nw.push(path); } 172 | }); 173 | } 174 | if ("el" in config) { 175 | config["el"]["source"].forEach(function(file) { 176 | var path = dir + file; 177 | if (el.indexOf(path) < 0) { el.push(path); } 178 | }); 179 | } 180 | // --- add Electron support --- 181 | // package.json に nw があり、el がない場合は、nw の設定を el にコピーして使用する 182 | // このコードブロックは将来不要になる予定 183 | if ("nw" in config && !("el" in config)) { 184 | config["nw"]["source"].forEach(function(file) { 185 | var path = dir + file; 186 | if (el.indexOf(path) < 0) { el.push(path); } 187 | }); 188 | } 189 | } 190 | } 191 | }); 192 | return { 193 | "nw": nw, 194 | "el": el, 195 | "node": node, 196 | "worker": worker, 197 | "browser": browser, 198 | "label": ModuleSystem_toUniqueArray(label) // ["@dev", "@debug", ...] 199 | }; 200 | } 201 | 202 | function ModuleSystem_toUniqueArray(source) { 203 | return source.reduce(function(result, value) { 204 | if (result.indexOf(value) < 0) { result.push(value); } 205 | return result; 206 | }, []); 207 | } 208 | 209 | function ModuleSystem_collectBuildTarget(json) { // @arg Object - package.json 210 | // @ret Object - { browser, worker, node, nw, el, sources, workDir } 211 | var wm = json.webmodule || {}; 212 | 213 | // --- collect source --- 214 | var browserSource = []; 215 | var workerSource = []; 216 | var nodeSource = []; 217 | var nwSource = []; 218 | var elSource = []; 219 | // --- collect output --- 220 | var browserOutput = ""; 221 | var workerOutput = ""; 222 | var nodeOutput = ""; 223 | var nwOutput = ""; 224 | var elOutput = ""; 225 | 226 | if (wm.browser) { 227 | browserSource = wm.browser.source; 228 | browserOutput = wm.browser.output; 229 | } 230 | if (wm.worker) { 231 | workerSource = wm.worker.source; 232 | workerOutput = wm.worker.output; 233 | } 234 | if (wm.node) { 235 | nodeSource = wm.node.source; 236 | nodeOutput = wm.node.output; 237 | } 238 | if (wm.nw) { 239 | nwSource = wm.nw.source; 240 | nwOutput = wm.nw.output; 241 | } 242 | if (wm.el) { 243 | elSource = wm.el.source; 244 | elOutput = wm.el.output; 245 | } 246 | var sources = ModuleSystem_toUniqueArray([].concat(browserSource, workerSource, nodeSource, nwSource, elSource)); 247 | var workDir = ""; 248 | var output = browserOutput || workerOutput || nodeOutput || nwOutput || elOutput || ""; 249 | 250 | if (output.indexOf("/") > 0) { 251 | workDir = output.split("/").slice(0, -1).join("/") + "/"; 252 | } 253 | 254 | return { 255 | browser: { 256 | output: browserOutput, 257 | source: browserSource, 258 | }, 259 | worker: { 260 | output: workerOutput, 261 | source: workerSource, 262 | }, 263 | node: { 264 | output: nodeOutput, 265 | source: nodeSource, 266 | }, 267 | nw: { 268 | output: nwOutput, 269 | source: nwSource, 270 | }, 271 | el: { 272 | output: elOutput, 273 | source: elSource, 274 | }, 275 | sources: sources, 276 | workDir: workDir 277 | }; 278 | } 279 | 280 | function ModuleSystem_upgradePackageJSON(pkg) { 281 | pkg = _upgradeXBuild(pkg); 282 | pkg = _upgradeBuileTarget(pkg); 283 | return pkg; 284 | } 285 | 286 | function _upgradeXBuild(pkg) { 287 | if (!("x-build" in pkg)) { return pkg; } 288 | 289 | // console.log(" upgrade x-build {...} to webmodule {...}"); 290 | 291 | var build = pkg["x-build"]; 292 | 293 | pkg.webmodule = { 294 | label: build.label, 295 | target: build.target, 296 | source: build.source, 297 | output: build.output 298 | }; 299 | delete pkg["x-build"]; 300 | return pkg; 301 | } 302 | 303 | function _upgradeBuileTarget(pkg) { 304 | // Before 305 | // "webmodule": { 306 | // "develop": false, 307 | // "label": ["@dev"], 308 | // "target": ["all"], <- remove this 309 | // "source": ["lib/REPOSITORY_NAME.js"], <- sprit this 310 | // "output": "release/REPOSITORY_NAME.min.js" <- sprit this 311 | // }, 312 | // 313 | // After 314 | // "webmodule": { 315 | // "develop": false, <- stay 316 | // "label": ["@dev"], <- stay 317 | // "browser": { <- add if target.has.browser 318 | // "source": ["lib/REPOSITORY_NAME.js"], 319 | // "output": "release/REPOSITORY_NAME.b.min.js", 320 | // }, 321 | // "worker": { <- add if target.has.worker 322 | // "source": ["lib/REPOSITORY_NAME.js"], 323 | // "output": "release/REPOSITORY_NAME.w.min.js", 324 | // }, 325 | // "node": { <- add if target.has.node 326 | // "source": ["lib/REPOSITORY_NAME.js"], 327 | // "output": "release/REPOSITORY_NAME.b.min.js", 328 | // }, 329 | // "nw": { <- add if target.has.node && target.has.browser 330 | // "source": ["lib/REPOSITORY_NAME.js"], 331 | // "output": "release/REPOSITORY_NAME.nw.min.js", 332 | // }, 333 | // "el": { <- add if target.has.node && target.has.browser 334 | // "source": ["lib/REPOSITORY_NAME.js"], 335 | // "output": "release/REPOSITORY_NAME.el.min.js", 336 | // } 337 | // }, 338 | // 339 | if (!("webmodule" in pkg) || !("target" in pkg["webmodule"])) { return pkg; } 340 | // var wm = pkg["webmodule"]; 341 | 342 | // console.log(" upgrade webmodule.target to webmodule{browser|worker|node}"); 343 | 344 | var result = JSON.parse(JSON.stringify(pkg)); 345 | 346 | result.webmodule = { 347 | develop: pkg.webmodule.develop || false, 348 | label: pkg.webmodule.label || ["@dev"] 349 | }; 350 | 351 | var target = pkg.webmodule.target.join(""); 352 | 353 | if ( /(all|browser)/i.test(target) ) { 354 | result.webmodule.browser = { 355 | source: pkg.webmodule.source, 356 | output: pkg.webmodule.output.replace(/min.js$/, "b.min.js") 357 | }; 358 | } 359 | if ( /(all|worker)/i.test(target) ) { 360 | result.webmodule.worker = { 361 | source: pkg.webmodule.source, 362 | output: pkg.webmodule.output.replace(/min.js$/, "w.min.js") 363 | }; 364 | } 365 | if ( /(all|node)/i.test(target) ) { 366 | result.webmodule.node = { 367 | source: pkg.webmodule.source, 368 | output: pkg.webmodule.output.replace(/min.js$/, "n.min.js") 369 | }; 370 | } 371 | if ( /(all)/i.test(target) || (/(browser)/i.test(target) && /(node)/i.test(target)) ) { 372 | result.webmodule.nw = { 373 | source: pkg.webmodule.source, 374 | output: pkg.webmodule.output.replace(/min.js$/, "nw.min.js") 375 | }; 376 | } 377 | if ( /(all)/i.test(target) || (/(browser)/i.test(target) && /(node)/i.test(target)) ) { 378 | result.webmodule.el = { 379 | source: pkg.webmodule.source, 380 | output: pkg.webmodule.output.replace(/min.js$/, "el.min.js") 381 | }; 382 | } 383 | return result; 384 | } 385 | 386 | function ModuleSystem_prettyPrint(str) { // @arg JSONString 387 | // @ret JSONString 388 | return str.replace(/: \[([^\]]*)\],/g, function(_, items) { 389 | return ': [' + items.trim().replace(/\s*\n+\s*/g, " ") + '],'; 390 | }); 391 | } 392 | 393 | // --- exports --------------------------------------------- 394 | if (typeof module !== "undefined") { 395 | module["exports"] = ModuleSystem; 396 | } 397 | global["ModuleSystem"] = ModuleSystem; 398 | 399 | })(GLOBAL); 400 | 401 | -------------------------------------------------------------------------------- /lib/Reflection.js: -------------------------------------------------------------------------------- 1 | // Reflection.js 2 | (function(global) { 3 | "use strict"; 4 | 5 | // --- dependency modules ---------------------------------- 6 | // --- define / local variables ---------------------------- 7 | var IGNORE_KEYWORDS = [ 8 | "webkitStorageInfo", 9 | "Infinity", 10 | "NaN", 11 | "arguments", 12 | "caller", 13 | "callee", 14 | "buffer", 15 | "byteOffset", 16 | "byteLength", // DataView, ArrayBuffer, Float32Array, ... 17 | "length", 18 | "String.prototype.help", 19 | "Function.prototype.help", 20 | "MediaError", 21 | "webkitOfflineAudioContext", // OfflineAudioContext 22 | "webkitAudioContext", // AudioContext 23 | "webkitIDBTransaction", // IDBTransaction 24 | "webkitIDBRequest", // IDBRequest 25 | "webkitIDBObjectStore", // IDBObjectStore 26 | "webkitIDBKeyRange", // IDBKeyRange 27 | "webkitIDBIndex", // IDBIndex 28 | "webkitIDBFactory", // IDBFactory 29 | "webkitIDBDatabase", // IDBDatabase 30 | "webkitIDBCursor", // IDBCursor 31 | "webkitIndexedDB", // indexedDB 32 | "webkitURL", // URL 33 | ]; 34 | var _syntaxHighlightData = { 35 | matcher: null, // /^\W(function|var|...|with)\W$/ 36 | keywords: null // /\\[^\n]+|.../ 37 | }; 38 | var ES6_SYNTAX_KEYWORDS = [ 39 | "\/\/[^\n]+", // // comment 40 | "\/[^\n\/]+\/", // /regexp/ 41 | "\"[^\n\"]*\"", // "string" 42 | "\'[^\n\']*\'" // 'string' 43 | ]; 44 | var ES6_IDENTIFY_KEYWORD = 45 | "function|var|this|self|that|if|else|in|typeof|instanceof|null|undefined|" + 46 | "try|catch|throw|finally|switch|case|default|for|while|do|break|continue|" + 47 | "return|new|debugger|void|delete|" + 48 | "enum|class|super|extends|implements|interface|private|protected|package|" + 49 | "static|public|export|import|yield|let|const|with"; 50 | 51 | var functionCache = global["WeakMap"] ? new global["WeakMap"]() : null; 52 | 53 | // --- class / interfaces ---------------------------------- 54 | function Reflection() { 55 | } 56 | 57 | Reflection["lang"] = ""; // Reference language. "", "en", "ja" 58 | 59 | Reflection["addIgnoreKeyword"] = Reflection_addIgnoreKeyword; // Reflection.addIgnoreKeyword(keywords:StringArray):void 60 | 61 | // --- path --- 62 | Reflection["resolve"] = Reflection_resolve; // Reflection.resolve(target:Function|String):Object 63 | // --- module --- 64 | Reflection["getModuleRepository"] = Reflection_getModuleRepository; // Reflection.getModuleRepository(moduleName:String):String 65 | // --- class --- 66 | Reflection["getBaseClassName"] = Reflection_getBaseClassName; // Reflection.getBaseClassName(value):String 67 | Reflection["getConstructorName"] = Reflection_getConstructorName; // Reflection.getConstructorName(value):String 68 | // --- function --- 69 | Reflection["parseFunction"] = Reflection_parseFunction; // Reflection.parseFunction(target:Function):Object 70 | Reflection["buildFunction"] = Reflection_buildFunction; // Reflection.buildFunction(declaration:Object):String 71 | // --- link --- 72 | Reflection["getSearchLink"] = Reflection_getSearchLink; // Reflection.getSearchLink(path:String):Object 73 | Reflection["getReferenceLink"] = Reflection_getReferenceLink; // Reflection.getReferenceLink(path:String):Object 74 | // --- syntax highlight --- 75 | Reflection["syntaxHighlight"] = Reflection_syntaxHighlight; // Reflection.syntaxHighlight(code:String, highlight:String, target:String = "console", style:Object = {}):StringArray 76 | 77 | // --- implements ------------------------------------------ 78 | function Reflection_addIgnoreKeyword(keywords) { // @arg StringArray 79 | // @desc add ignore keywords. 80 | Array.prototype.push.apply(IGNORE_KEYWORDS, keywords); 81 | } 82 | 83 | function Reflection_resolve(target) { // @arg Function|String target function - Object.freeze or "Object.freeze" 84 | // callback(detach:Boolean):void 85 | // @ret Object - { path, fn } 86 | // @return.path String - function absoulute path. eg: ["Object", "freeze"] 87 | // @return.fn Function - function. eg: Object.freeze 88 | // @desc resolve function absolute path. 89 | 90 | //{@dev 91 | if (!/function|string/.test(typeof target)) { 92 | throw new Error("Reflection.resolve(target): target is not Function or String."); 93 | } 94 | //}@dev 95 | 96 | var path = ""; 97 | var fn = null; 98 | 99 | switch (typeof target) { 100 | case "function": 101 | path = _convertFunctionToPathString(global, target, ["Object", "Function", "Array", "String", "Number"]) || // inject 102 | _convertFunctionToPathString(global.WebModule, target, []); // inject 103 | fn = target; 104 | break; 105 | case "string": 106 | target = _extractSharp(target); 107 | path = target; 108 | fn = _convertPathStringToFunction(target); 109 | if (!fn) { 110 | fn = _convertPathStringToFunction("WebModule." + target); 111 | if (fn) { 112 | path = "WebModule." + target; 113 | } 114 | } 115 | } 116 | return { "path": path, "fn": fn }; 117 | } 118 | 119 | function _convertPathStringToFunction(target) { // @arg String - function path. "Object.freeze" 120 | // @ret Function|null - function object. Object.freeze 121 | return target.split(".").reduce(function(parent, token) { 122 | return ( parent && (token in parent) ) ? parent[token] 123 | : null; 124 | }, global); 125 | } 126 | 127 | function _convertFunctionToPathString(root, // @arg Object - find root object. global or global.WebModule 128 | target, // @arg Function - function object. Object.freeze 129 | injectKeys) { // @arg StringArray - ["Object", "Function", ...] 130 | // @ret String - function path. "Object.freeze" 131 | var path = ""; 132 | var rootKeys = _enumKeys(root).sort(); 133 | 134 | Array.prototype.unshift.apply(rootKeys, injectKeys); 135 | 136 | for (var i = 0, iz = rootKeys.length; i < iz && !path; ++i) { 137 | var className = rootKeys[i]; 138 | 139 | if ( IGNORE_KEYWORDS.indexOf(className) < 0 && 140 | root[className] != null && 141 | /object|function/.test(typeof root[className]) ) { 142 | 143 | var klass = root[className]; 144 | 145 | if (klass === target) { 146 | path = className; 147 | } else { 148 | path = _findClassMember(target, root, className, _enumKeys(klass)); 149 | 150 | if ( !path && ("prototype" in klass) ) { 151 | path = _findPropertyMember(target, root, className, 152 | _enumKeys(klass["prototype"])); 153 | } 154 | } 155 | } 156 | } 157 | return path.replace(/^global\./i, ""); 158 | } 159 | 160 | function _enumKeys(object) { 161 | return (Object["getOwnPropertyNames"] || Object["keys"])(object); 162 | } 163 | 164 | function _findClassMember(target, root, className, keys) { 165 | for (var i = 0, iz = keys.length; i < iz; ++i) { 166 | var key = keys[i]; 167 | var path = className + "." + key; 168 | 169 | if (IGNORE_KEYWORDS.indexOf(path) < 0 && 170 | IGNORE_KEYWORDS.indexOf(key) < 0) { 171 | 172 | try { 173 | if (root[className][key] === target) { 174 | return path; // resolved 175 | } 176 | } catch (o_o) {} 177 | } 178 | } 179 | return ""; 180 | } 181 | 182 | function _findPropertyMember(target, root, className, keys) { 183 | for (var i = 0, iz = keys.length; i < iz; ++i) { 184 | var key = keys[i]; 185 | var path = className + ".prototype." + key; 186 | 187 | if (IGNORE_KEYWORDS.indexOf(path) < 0 && 188 | IGNORE_KEYWORDS.indexOf(key) < 0) { 189 | 190 | try { 191 | if (root[className]["prototype"][key] === target) { 192 | return path; // resolved 193 | } 194 | } catch (o_o) {} 195 | } 196 | } 197 | return ""; 198 | } 199 | 200 | function Reflection_parseFunction(target) { // @arg Function 201 | // @ret Object - { name:String, head:StringArray, body:StringArray, arg:StringArray, ret:StringArray } 202 | if (functionCache && functionCache.has(target)) { 203 | return functionCache.get(target); 204 | } 205 | var result = _splitFunctionDeclaration(target + ""); // { head, body } 206 | 207 | result["name"] = target["name"]; 208 | result["arg"] = _getArg(result["head"]); 209 | result["ret"] = _getRet(result["head"]); 210 | 211 | if (functionCache) { 212 | functionCache.set(target, result); 213 | } 214 | return result; 215 | } 216 | 217 | function Reflection_buildFunction(declaration) { // @arg Object - { head, body, arg, ret } 218 | return ""; // TODO impl 219 | } 220 | 221 | function _getArg(head) { // @arg StringArray - [line, ...] 222 | // @ret Object - [{ name, type, optional, comment }, ...] 223 | // get @arg attribute. 224 | // 225 | // function Foo_add(name, // @arg Function|String = "" comment 226 | // key ) { // @arg String comment 227 | // // @ret ResultType comment 228 | // ~~~~~ ~~~~~~~~~~~~~~~ ~~ ~~~~~~~ 229 | // name type opt comment 230 | // } 231 | 232 | var result = []; 233 | var format = /^([\w\|\/,]+)\s*(=\s*("[^"]*"|'[^']*'|\S+))?\s*([^\n]*)$/; 234 | 235 | head.forEach(function(line, lineNumber) { 236 | if (/@arg|@var_args/.test(line)) { 237 | if (lineNumber === 0) { 238 | line = _removeFunctionDeclarationString(line); 239 | } 240 | var nameType = line.split(/@arg|@var_args/); 241 | var name = nameType[0].replace(/\W+/g, "").trim(); 242 | var type = ""; 243 | var optional = ""; 244 | var comment = ""; 245 | var token = format.exec(nameType[1].trim()); 246 | 247 | if (token) { 248 | type = token[1]; 249 | optional = token[3] || ""; 250 | comment =(token[4] || "").replace(/^[ :#\-]+/, ""); 251 | } 252 | result.push({ "name": name, "type": type, 253 | "optional": optional, "comment": comment }); 254 | } 255 | }); 256 | return result; 257 | } 258 | 259 | function _getRet(head) { // @arg StringArray - [line, ...] 260 | // @ret Object - [{ types, comment }, ...] 261 | // get @ret attribute. 262 | // 263 | // function Foo_add(name, // @arg Function|String = "" comment 264 | // key ) { // @arg String comment 265 | // // @ret ResultType comment 266 | // ~~~~~~~~~~~~~~~ ~~~~~~~ 267 | // type comment 268 | // } 269 | 270 | var result = []; 271 | var format = /^([\w\|\/,]+)\s+([^\n]*)$/; 272 | 273 | head.forEach(function(line, lineNumber) { 274 | if (/@ret/.test(line)) { 275 | if (lineNumber === 0) { 276 | line = _removeFunctionDeclarationString(line); 277 | } 278 | var typeComment = line.split(/@ret/); // -> [" // ", " ResultType comment"] 279 | var type = ""; 280 | var comment = ""; 281 | var token = format.exec(typeComment[1].trim()); 282 | 283 | if (token) { 284 | type = token[1]; 285 | comment =(token[2] || "").replace(/^[ :#\-]+/, ""); 286 | } 287 | result.push({ "type": type, "comment": comment }); 288 | } 289 | }); 290 | return result; 291 | } 292 | 293 | function _splitFunctionDeclaration(sourceCode) { // @arg String - function code 294 | // @ret Object - { head:StringArray, body:StringArray } 295 | // 296 | // sourceCode: 297 | // 298 | // "function foo() { // @ret String\n 299 | // return '';\n 300 | // }" 301 | // 302 | // result: { 303 | // head: [ 304 | // "function foo() { // @ret String" 305 | // ], 306 | // body: [ 307 | // " return '';", 308 | // "}" 309 | // ] 310 | // } 311 | // 312 | var code = sourceCode.trim(); 313 | var lines = code.split("\n"); 314 | var basePos = lines[0].indexOf("//"); 315 | var min = 10; 316 | 317 | if (basePos >= min) { // "function foo() {" 318 | for (var i = 1, iz = lines.length; i < iz; ++i) { 319 | var pos = lines[i].indexOf("//"); // get header comment position(column) 320 | 321 | if (pos < min || pos < basePos) { 322 | break; 323 | } 324 | } 325 | } 326 | return { "head": lines.slice(0, i), "body": lines.slice(i) }; 327 | } 328 | 329 | function _removeFunctionDeclarationString(sourceCode) { // @arg String 330 | // @ret String 331 | // 332 | // sourceCode: 333 | // "function xxx(...) { }" 334 | // 335 | // result: 336 | // "(...) { }" 337 | // 338 | return sourceCode.replace(/^function\s+[^\x28]+/, ""); 339 | } 340 | 341 | function _extractSharp(path) { // @arg String - "Array#forEach" 342 | // @ret String - "Array.prototype.forEach" 343 | return path.trim().replace("#", ".prototype."); 344 | } 345 | 346 | function Reflection_getModuleRepository(moduleName) { // @arg String - path. "Reflection" 347 | // @ret String 348 | // @desc get WebModule repository url. 349 | if (moduleName in global["WebModule"]) { 350 | var repository = global["WebModule"][moduleName]["repository"] || ""; 351 | 352 | if (repository) { 353 | return repository.replace(/\/+$/, ""); // trim tail slash 354 | } 355 | } 356 | if (moduleName in global) { 357 | var repository = global[moduleName]["repository"] || ""; 358 | 359 | if (repository) { 360 | return repository.replace(/\/+$/, ""); // trim tail slash 361 | } 362 | } 363 | return ""; // global["WebModule"][moduleName] or global[moduleName] not found 364 | } 365 | 366 | function Reflection_getSearchLink(path) { // @arg String - "Object.freeze" 367 | // @ret Object - { title:String, url:URLString } 368 | // @desc get Google search link. 369 | // 370 | // Google Search( Array.isArray ): 371 | // http://www.google.com/search?lr=lang_ja&ie=UTF-8&oe=UTF-8&q=Array.isArray 372 | // 373 | return { 374 | "title": "Google Search( " + path + " ):", 375 | "url": _createGoogleSearchURL(path) 376 | }; 377 | } 378 | 379 | function _createGoogleSearchURL(keyword) { // @arg String - search keyword. 380 | // @ret String - "http://..." 381 | return "http://www.google.com/search?lr=lang_" + 382 | _getLanguage() + "&q=" + 383 | encodeURIComponent(keyword); 384 | } 385 | 386 | function Reflection_getReferenceLink(path) { // @arg String - "Object.freeze" 387 | // @ret Object - { title:String, url:URLString } 388 | // @desc get JavaScript/WebModule reference link. 389 | if ( /^WebModule\./.test(path) ) { 390 | path = path.replace(/^WebModule\./, ""); 391 | } 392 | var className = path.split(".")[0] || ""; // "Array.prototype.forEach" -> ["Array", "prototype", "forEach"] -> "Array" 393 | var repository = Reflection_getModuleRepository(className); // "https://github.com/uupaa/Help.js" 394 | 395 | // 396 | // JavaScript API( Array.isArray ) Reference: 397 | // http://www.google.com/search?btnI=I%27m+Feeling+Lucky&lr=lang_ja&ie=UTF-8&oe=UTF-8&q=MDN%20Array.isArray 398 | // 399 | // WebModule Reference: 400 | // https://github.com/uupaa/PageVisibilityEvent.js/wiki/PageVisibilityEvent# 401 | // 402 | if (/native code/.test(global[className] + "")) { 403 | return { 404 | "title": "JavaScript Reference( " + path + " ):", 405 | "url": _createGoogleImFeelingLuckyURL(path, "MDN") 406 | }; 407 | } else if (repository && /github/i.test(repository)) { 408 | return { 409 | "title": "WebModule Reference:", 410 | "url": _createGitHubWikiURL(repository, className, path) 411 | }; 412 | } 413 | return null; 414 | } 415 | 416 | function _createGoogleImFeelingLuckyURL(keyword, // @arg String - search keyword. 417 | provider) { // @arg String - search providoer. 418 | // @ret String - "http://..." 419 | // @desc create I'm feeling lucky url 420 | return "http://www.google.com/search?btnI=I%27m+Feeling+Lucky&lr=lang_" + 421 | _getLanguage() + "&q=" + provider + "%20" + 422 | encodeURIComponent(keyword); 423 | } 424 | 425 | function _createGitHubWikiURL(baseURL, // @arg String - "http://..." 426 | wikiPageName, // @arg String - "Foo" 427 | hash) { // @arg String - "Foo#add" 428 | // replace characters 429 | // space -> "-" 430 | // hyphen -> "-" 431 | // underbar -> "_" 432 | // alphabet -> alphabet 433 | // number -> number 434 | // other -> "" 435 | // unicode -> encodeURIComponent(unicode) 436 | hash = hash.replace(/[\x20-\x7e]/g, function(match) { 437 | var result = / |-/.test(match) ? "-" 438 | : /\W/.test(match) ? "" 439 | : match; 440 | 441 | return result; 442 | }); 443 | 444 | // {baseURL}/wiki/{wikiPageName} or 445 | // {baseURL}/wiki/{wikiPageName}#{hash} 446 | var result = []; 447 | 448 | result.push( baseURL.replace(/\/+$/, ""), // remove tail slash 449 | "/wiki/", 450 | wikiPageName + "#" ); 451 | 452 | if (wikiPageName !== hash) { 453 | result.push( "wiki-", encodeURIComponent(hash.toLowerCase()) ); 454 | } 455 | return result.join(""); 456 | } 457 | 458 | function _getLanguage() { // @ret String - "en", "ja" ... 459 | if (Reflection["lang"]) { 460 | return Reflection["lang"]; 461 | } 462 | if (global["navigator"]) { 463 | return global["navigator"]["language"]; 464 | } 465 | return "en"; 466 | } 467 | 468 | function Reflection_getBaseClassName(value) { // @arg Any - instance, exclude null and undefined. 469 | // @ret String 470 | // Object.prototype.toString.call(new Error()); -> "[object Error]" 471 | // Object.prototype.toString.call(new TypeError()); -> "[object Error]" 472 | return Object.prototype.toString.call(value).split(" ")[1].slice(0, -1); // -> "Error" 473 | } 474 | 475 | function Reflection_getConstructorName(value) { // @arg Any - instance, exclude null and undefined. 476 | // @ret String 477 | // Reflection_getConstructorName(new (function Aaa() {})); -> "Aaa" 478 | return value.constructor["name"] || 479 | (value.constructor + "").split(" ")[1].split("\x28")[0]; // for IE 480 | } 481 | 482 | function Reflection_syntaxHighlight(code, // @arg String - source code 483 | highlight, // @arg String - highlight keyword 484 | target, // @arg String = "console" - target environment. 485 | style) { // @arg Object = {} - { syntax, comment, literal, highlight } 486 | // @style.syntax CSSStyleTextString = "color:#03f" 487 | // @style.comment CSSStyleTextString = "color:#3c0" 488 | // @style.literal CSSStyleTextString = "color:#f6c" 489 | // @style.highlight CSSStyleTextString = "background:#ff9;font-weight:bold" 490 | // @ret StringArray 491 | switch (target || "console") { 492 | case "console": 493 | return _syntaxHighlightForConsole(code, highlight, style || {}); 494 | } 495 | return []; 496 | } 497 | 498 | function _syntaxHighlightForConsole(code, highlight, style) { 499 | var styleSyntax = style["syntax"] || "color:#03f"; 500 | var styleComment = style["comment"] || "color:#3c0"; 501 | var styleLiteral = style["literal"] || "color:#f6c"; 502 | var styleHighlight = style["highlight"] || "background:#ff9;font-weight:bold"; 503 | var highlightData = _createSyntaxHighlightData(); 504 | 505 | var styleDeclaration = []; 506 | var rexSource = highlight ? (highlight + "|" + highlightData.keyword.join("|")) 507 | : highlightData.keyword.join("|"); 508 | var rex = new RegExp("(" + rexSource + ")", "g"); 509 | var body = ("\n" + code + "\n").replace(/%c/g, "% c"). 510 | replace(rex, function(_, match) { 511 | if (match === highlight) { 512 | styleDeclaration.push(styleHighlight, ""); 513 | return "%c" + highlight + "%c"; 514 | } else if (/^\/\/[^\n]+$/.test(match)) { 515 | styleDeclaration.push(styleComment, ""); 516 | return "%c" + match + "%c"; 517 | } else if (/^(\/[^\n\/]+\/|\"[^\n\"]*\"|\'[^\n\']*\')$/.test(match)) { 518 | styleDeclaration.push(styleLiteral, ""); 519 | return "%c" + match + "%c"; 520 | } else if (highlightData.matcher.test(match)) { 521 | styleDeclaration.push(styleSyntax, ""); 522 | return "%c" + match + "%c"; 523 | } 524 | return match; 525 | }).trim(); 526 | return [body].concat(styleDeclaration); 527 | } 528 | 529 | function _createSyntaxHighlightData() { 530 | if (!_syntaxHighlightData.matcher) { // cached? 531 | _syntaxHighlightData.matcher = 532 | new RegExp("^\\W(" + ES6_IDENTIFY_KEYWORD + ")\\W$"); 533 | _syntaxHighlightData.keyword = [].concat(ES6_SYNTAX_KEYWORDS, 534 | ES6_IDENTIFY_KEYWORD.split("|").map(function(keyword) { 535 | return "\\W" + keyword + "\\W"; 536 | })); 537 | } 538 | return _syntaxHighlightData; 539 | } 540 | 541 | // --- exports --------------------------------------------- 542 | if (typeof module !== "undefined") { 543 | module["exports"] = Reflection; 544 | } 545 | global["Reflection"] = Reflection; 546 | 547 | })(GLOBAL); 548 | 549 | -------------------------------------------------------------------------------- /lib/Task.js: -------------------------------------------------------------------------------- 1 | // Task.js 2 | (function(global) { 3 | "use strict"; 4 | 5 | // --- dependency modules ---------------------------------- 6 | // --- define / local variables ---------------------------- 7 | var _taskInstances = {}; // instances. { "taskName@counter": TaskInstance, ... } 8 | var _taskNumber = 0; 9 | 10 | function NOP() {} 11 | 12 | // --- class / interfaces ---------------------------------- 13 | function Task(taskCount, // @arg Integer - user task count, value from 1. 14 | callback, // @arg Function|Task = null - callback(err:Error, buffer:Array) 15 | options) { // @arg Object = {} - { tick, name, buffer } 16 | // @options.tick Function = null - tick(taskName) callback. 17 | // @options.name String = "anonymous" - task name. 18 | // @options.buffer Array = [] - buffer. 19 | // @desc Counter based task executor. 20 | 21 | options = options || {}; 22 | callback = callback || NOP; 23 | 24 | var junction = callback instanceof Task; 25 | var tick = options["tick"] || null; 26 | var name = options["name"] || "anonymous"; 27 | var buffer = options["buffer"] || (junction ? callback["buffer"]() : []); // Junction -> Buffer share 28 | 29 | this["name"] = name + "@" + (++_taskNumber); // String: "task@1" 30 | this._ = { 31 | tick: tick, // Function: 32 | buffer: buffer, // Array: 33 | callback: callback, // Function|Task: finished callback. 34 | junction: junction, // Boolean: callback is Junction. 35 | taskCount: taskCount, // Number: user task count. 36 | missableCount: 0, // Integer: number of missable count. 37 | passedCount: 0, // Integer: Task#pass() called count. 38 | missedCount: 0, // Integer: Task#miss() called count. 39 | message: "", // String: new Error(message) 40 | state: "" // String: current state. ""(progress), "pass", "miss", "exit" 41 | }; 42 | _taskInstances[this["name"]] = this; // register task instance. 43 | if (!taskCount) { 44 | _update(this, "init"); // user task count is zero -> finished. 45 | } 46 | } 47 | 48 | Task["prototype"] = { 49 | "constructor": Task, // new Task(tackCount:Integer, callback:Function|Task = null, options:Object = {}) 50 | // --- buffer accessor --- 51 | "pop": Task_pop, // Task#pop():Any|undefined 52 | "push": Task_push, // Task#push(value:Any):this 53 | "shift": Task_shift, // Task#shift():Any|undefined 54 | "unshift": Task_unshift, // Task#unshift(value:Any):this 55 | "set": Task_set, // Task#set(key:String, value:Any):this 56 | // --- flow state --- 57 | "done": Task_done, // Task#done(err:Error|null):this 58 | "pass": Task_pass, // Task#pass():this 59 | "miss": Task_miss, // Task#miss():this 60 | "exit": Task_exit, // Task#exit():this 61 | // --- closure function --- 62 | "passfn": Task_passfn, // Task#passfn():TaskPassClosureFunction 63 | "missfn": Task_missfn, // Task#missfn():TaskMissClosureFunction 64 | // --- utility --- 65 | "state": Task_state, // Task#state():String 66 | "buffer": Task_buffer, // Task#buffer():Array|null 67 | "extend": Task_extend, // Task#extend(count:Integer):this 68 | "message": Task_message, // Task#message(message:Error|String):this 69 | "missable": Task_missable, // Task#missable(count:Integer):this 70 | "isFinished": Task_isFinished // Task#isFinished():Boolean 71 | }; 72 | Task["dump"] = Task_dump; // Task.dump(filter:String = ""):Object 73 | Task["clear"] = Task_clear; // Task.clear():void 74 | Task["drop"] = Task_clear; // [DEPRECATED] Task.drop():void 75 | Task["flatten"] = Task_flatten; // Task.flatten(source:Array):Array 76 | Task["arraynize"] = Task_arraynize; // Task.arraynize(source:Array):Array 77 | Task["objectize"] = Task_objectize; // Task.objectize(source:Array):Object 78 | 79 | // --- task runner --- 80 | Task["run"] = Task_run; // Task.run(taskPlan:String, 81 | // taskMap:TaskMapObject|TaskMapArray, 82 | // callback:Function|Task = null, 83 | // options:Object = {}):Task 84 | Task["loop"] = Task_loop; // Task.loop(source:Object|Array, 85 | // tick:Function, 86 | // callback:Function|Task = null, 87 | // options:Object = {}):Task 88 | // --- implements ------------------------------------------ 89 | function Task_pop() { // @ret Any|undefined 90 | if (this._.buffer) { 91 | return this._.buffer.pop(); 92 | } 93 | return this; 94 | } 95 | function Task_push(value) { // @arg Any 96 | // @ret this 97 | if (this._.buffer) { 98 | this._.buffer.push(value); 99 | } 100 | return this; 101 | } 102 | function Task_shift() { // @ret Any|undefined 103 | if (this._.buffer) { 104 | return this._.buffer.shift(); 105 | } 106 | return this; 107 | } 108 | function Task_unshift(value) { // @arg Any 109 | // @ret this 110 | if (this._.buffer) { 111 | this._.buffer.unshift(value); 112 | } 113 | return this; 114 | } 115 | 116 | function Task_set(key, // @arg String 117 | value) { // @arg Any 118 | // @ret this 119 | if (this._.buffer) { 120 | this._.buffer[key] = value; 121 | } 122 | return this; 123 | } 124 | 125 | function Task_done(err) { // @arg Error|null 126 | // @ret this 127 | // @desc err is call Task#message(err.message).miss() 128 | // !err is call Task#pass() 129 | var miss = err instanceof Error; 130 | 131 | if (miss) { 132 | this["message"](err["message"]); 133 | } 134 | return miss ? this["miss"]() 135 | : this["pass"](); 136 | } 137 | 138 | function Task_pass() { // @ret this 139 | // @desc pass a user task. 140 | if (this._.tick) { 141 | this._.tick(this["name"]); // tick callback(taskName) 142 | } 143 | return _update(this, "pass"); 144 | } 145 | 146 | function Task_miss() { // @ret this 147 | // @desc miss a user task. 148 | if (this._.tick) { 149 | this._.tick(this["name"]); // tick callback(taskName) 150 | } 151 | return _update(this, "miss"); 152 | } 153 | 154 | function Task_exit() { // @ret this 155 | // @desc exit the Task. 156 | return _update(this, "exit"); 157 | } 158 | 159 | function _update(that, method) { // @ret this 160 | var _ = that._; 161 | 162 | if (_.state === "") { // task in progress. 163 | // --- update current state --- 164 | switch (method) { 165 | case "init": _.state = _judgeState(_); break; 166 | case "pass": ++_.passedCount; _.state = _judgeState(_); break; 167 | case "miss": ++_.missedCount; _.state = _judgeState(_); break; 168 | case "exit": _.state = "exit"; 169 | } 170 | // --- finishing --- 171 | if (_.state) { // task was finished. state = "pass" or "miss" or "exit" 172 | if (_.junction) { 173 | // bubble up message and state. 174 | _.callback["message"](_.message); // call Junction#message(...) 175 | _.callback[_.state](); // call Junction#pass() or #miss() or #exit() 176 | } else { 177 | _.callback(_createError(that), _.buffer); 178 | } 179 | delete _taskInstances[that["name"]]; // [!] GC 180 | _.tick = null; // [!] GC 181 | _.buffer = null; // [!] GC 182 | _.callback = null; // [!] GC 183 | } 184 | } 185 | return that; 186 | } 187 | 188 | function _judgeState(_) { // @ret String - "miss" or "pass" or ""(progress) 189 | return _.missedCount > _.missableCount ? "miss" 190 | : _.passedCount >= _.taskCount ? "pass" 191 | : ""; 192 | } 193 | 194 | function _createError(that) { // @ret Error|null 195 | if (that._.state === "pass") { 196 | return null; 197 | } 198 | return new Error(that._.message || ("Error: " + that["name"])); 199 | } 200 | 201 | function Task_passfn() { // @ret TaskPassClosureFunction 202 | // @desc pass a user task. 203 | var that = this; 204 | 205 | return function() { that["pass"](); }; 206 | } 207 | 208 | function Task_missfn() { // @ret TaskMissClosureFunction 209 | // @desc miss a user task. 210 | var that = this; 211 | 212 | return function() { that["miss"](); }; 213 | } 214 | 215 | function Task_state() { // @ret String - task state "" / "pass" / "miss" / "exit" 216 | // @desc get state 217 | return this._.state; 218 | } 219 | 220 | function Task_buffer() { // @ret Array|null - task finished is null. 221 | return this._.buffer; 222 | } 223 | 224 | function Task_extend(count) { // @arg Integer - task count 225 | // @ret this 226 | // @desc extend task count. 227 | this._.taskCount += count; 228 | return this; 229 | } 230 | 231 | function Task_message(message) { // @arg Error|String - message. 232 | // @ret this 233 | // @desc set message 234 | this._.message = message["message"] || message; 235 | return this; 236 | } 237 | 238 | function Task_missable(count) { // @arg Integer - missable count 239 | // @ret this 240 | // @desc extend missable count. 241 | this._.missableCount += count; 242 | return this; 243 | } 244 | 245 | function Task_isFinished() { // @ret Boolean - true is finished 246 | return this._.state !== ""; 247 | } 248 | 249 | function Task_dump(filter) { // @arg String = "" - task name filter. 250 | // @ret Object - task info snap shot. 251 | // @desc dump snapshot. 252 | var rv = {}; 253 | 254 | for (var taskName in _taskInstances) { 255 | if ( !filter || filter === taskName.split("@")[0] ) { 256 | var _ = _taskInstances[taskName]._; 257 | 258 | rv[taskName] = { 259 | "junction": _.junction, 260 | "taskCount": _.taskCount, 261 | "missableCount":_.missableCount, 262 | "passedCount": _.passedCount, 263 | "missedCount": _.missedCount, 264 | "state": _.state 265 | }; 266 | } 267 | } 268 | return JSON.parse( JSON.stringify(rv) ); // dead copy 269 | } 270 | 271 | function Task_clear() { // @desc clear snapshot. 272 | _taskInstances = {}; // [!] GC 273 | _taskNumber = 0; // [!] reset 274 | } 275 | 276 | function Task_flatten(source) { // @arg Array 277 | // @ret Array 278 | return Array.prototype.concat.apply([], source); 279 | } 280 | 281 | function Task_arraynize(source) { // @arg Array 282 | // @ret Array 283 | return Array.prototype.slice.call(source); 284 | } 285 | 286 | function Task_objectize(source) { // @arg Array 287 | // @ret Object 288 | return Object.keys(source).reduce(function(result, key) { 289 | result[key] = source[key]; 290 | return result; 291 | }, {}); 292 | } 293 | 294 | function Task_run(taskPlan, // @arg String - plan. "a > b + c > d" 295 | taskMap, // @arg TaskMapObject|TaskMapArray - { a:fn, b:fn, c:fn, d:fn }, [fn, ...] 296 | // fn(task:Task, arg:Any, groupIndex:Integer):void 297 | callback, // @arg Function|Task = null - finished callback. callback(err:Error, buffer:Array) 298 | options) { // @arg Object = {} { arg, name, buffer } 299 | // @options.arg Any = null - task argument. 300 | // @options.name String = "Task.run" - junction task name. 301 | // @options.buffer Array = [] - shared buffer. 302 | // @ret Task (as Junction) 303 | options = options || {}; 304 | callback = callback || NOP; 305 | 306 | var arg = options["arg"] || null; 307 | var name = options["name"] || "Task.run"; 308 | var buffer = options["buffer"] || (callback instanceof Task ? callback["buffer"]() : []); // Junction -> Buffer share 309 | 310 | var line = null; 311 | 312 | // parse("a > b + c > d") -> [ ["a"], ["b", "c"], ["d"] ] 313 | // ~~~ ~~~ ~~~ ~~~ <--- 4 user tasks 314 | // ~~~~~ ~~~~~~~~~~ ~~~~~ <--- 3 user task groups 315 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <--- line (serialized task group) 316 | if (taskPlan) { 317 | line = JSON.parse("[[" + taskPlan.replace(/\+/g, ","). // "a > b , c > d" 318 | replace(/>/g, "],["). // "a ],[ b , c ],[ d" 319 | replace(/(\w+)/g, '"$1"') + "]]"); // '"a" ],[ "b" , "c" ],[ "d"' 320 | } else { 321 | line = JSON.parse('[["' + Object.keys(taskMap).join('"],["') + '"]]'); 322 | } 323 | 324 | var junction = new Task(line.length, callback, { "name": name, "buffer": buffer }); 325 | var param = { junction: junction, line: line, groupIndex: 0, taskMap: taskMap, arg: arg }; 326 | 327 | _nextGroup(param); 328 | return junction; 329 | } 330 | 331 | function _nextGroup(param) { 332 | if (!param.junction["isFinished"]()) { 333 | // --- create task group --- 334 | var taskGroup = param.line[param.groupIndex++]; // ["a"] or ["b", "c"] or ["d"] 335 | 336 | var groupJunction = new Task(taskGroup.length, function(err) { 337 | param.junction["done"](err); 338 | if (!err) { 339 | _nextGroup(param); // recursive call 340 | } 341 | }, { "buffer": param.junction["buffer"]() }); 342 | 343 | for (var i = 0, iz = taskGroup.length; i < iz; ++i) { 344 | _callUserTask(param, taskGroup[i], groupJunction); 345 | } 346 | } 347 | 348 | function _callUserTask(param, taskName, groupJunction) { 349 | var task = new Task(1, groupJunction, { "name": taskName }); 350 | 351 | if (taskName in param.taskMap) { 352 | try { 353 | param.taskMap[taskName](task, param.arg, param.groupIndex - 1); // call userTask(task, arg, groupIndex) { ... } 354 | } catch (err) { 355 | if (err) { 356 | if (err.stack) { 357 | console.error(err.stack); 358 | } else { 359 | console.error(err.message); 360 | } 361 | } 362 | task["done"](err); 363 | } 364 | } else if ( isFinite(taskName) ) { // isFinite("1000") -> sleep(1000) task 365 | setTimeout(function() { 366 | task["pass"](); 367 | }, parseInt(taskName, 10) | 0); 368 | } 369 | } 370 | } 371 | 372 | function Task_loop(source, // @arg Object|Array - for loop and for-in loop data. [1, 2, 3], { a: 1, b: 2, c: 3 } 373 | tick, // @arg Function - tick callback function. tick(task:Task, key:String, source:Object/Array):void 374 | callback, // @arg Function|Task = null - finished callback(err:Error, buffer:Array) 375 | options) { // @arg Object = {} - { arg, name, buffer } 376 | // @options.arg Any = null - task argument. 377 | // @options.name String = "Task.loop" - junction task name. 378 | // @options.buffer Array = [] - shared buffer. 379 | // @ret Task Junction 380 | 381 | var keys = Object.keys(source); 382 | var taskPlan = new Array(keys.length + 1).join("_").split("").join(">"); // "_>_>_ ..." 383 | var taskMap = { 384 | "_": function(task, arg, groupIndex) { 385 | tick(task, keys[groupIndex], source); 386 | } 387 | }; 388 | 389 | options = options || {}; 390 | options["name"] = options["name"] || "Task.loop"; 391 | 392 | return Task_run(taskPlan, taskMap, callback, options); 393 | } 394 | 395 | // --- exports --------------------------------------------- 396 | if (typeof module !== "undefined") { 397 | module["exports"] = Task; 398 | } 399 | global["_TestTask_"] = Task; 400 | 401 | })(GLOBAL); 402 | 403 | -------------------------------------------------------------------------------- /lib/Test.js: -------------------------------------------------------------------------------- 1 | // Test.js 2 | (function(global) { 3 | "use strict"; 4 | 5 | // --- dependency modules ---------------------------------- 6 | var Task = global["_TestTask_"]; 7 | 8 | // --- define / local variables ---------------------------- 9 | var STYLISH = global["navigator"] && /Chrome/.test(global["navigator"]["userAgent"] || ""); 10 | 11 | // console colors 12 | var ERR = "\u001b[31m"; 13 | var WARN = "\u001b[33m"; 14 | var INFO = "\u001b[32m"; 15 | var CLR = "\u001b[0m"; 16 | var GHOST = "\uD83D\uDC7B"; 17 | var BEER = "\uD83C\uDF7B"; 18 | 19 | // --- class / interfaces ---------------------------------- 20 | function Test(moduleName, // @arg String|StringArray - target modules. 21 | options) { // @arg Object = {} - { disable, browser, worker, node, nw, el, button, both, ignoreError } 22 | // @options.disable Boolean = false - Disable all tests. 23 | // @options.browser Boolean = false - Enable the browser test. 24 | // @options.worker Boolean = false - Enable the webWorker test. 25 | // @options.node Boolean = false - Enable the node.js test. 26 | // @options.nw Boolean = false - Enable the NW.js test. 27 | // @options.el Boolean = false - Enable the Electron (render process) test. 28 | // @options.button Boolean = false - Show test buttons. 29 | // @options.both Boolean = false - Test the primary and secondary module. 30 | // @options.ignoreError Boolean = false - ignore error 31 | // @options.callback Function = null - callback():void 32 | // @options.errorback Function = null - errorback(err:Error):void 33 | options = options || {}; 34 | 35 | this._testCases = []; 36 | this._secondary = false; // using secondary module 37 | this._module = Array.isArray(moduleName) ? moduleName : [moduleName]; 38 | this._browser = options["browser"] || false; 39 | this._worker = options["worker"] || false; 40 | this._node = options["node"] || false; 41 | this._nw = options["nw"] || false; 42 | this._el = options["el"] || false; 43 | this._button = options["button"] || false; 44 | this._both = options["both"] || false; 45 | this._ignoreError = options["ignoreError"] || false; 46 | this._callback = options["callback"] || function() {}; 47 | this._errorback = options["errorback"] || function() {}; 48 | 49 | if (options["disable"]) { 50 | this._browser = false; 51 | this._worker = false; 52 | this._node = false; 53 | this._nw = false; 54 | this._el = false; 55 | this._button = false; 56 | this._both = false; 57 | } 58 | } 59 | 60 | Test["prototype"]["add"] = Test_add; // Test#add(cases:TestFunction|TestFunctionArray = null):this 61 | Test["prototype"]["run"] = Test_run; // Test#run():TestFunctionArray 62 | 63 | // --- implements ------------------------------------------ 64 | function Test_add(testCases) { // @arg TestFunction|TestFunctionArray = null - [fn, ...] 65 | // @ret this 66 | // @desc add test cases. 67 | if (testCases) { 68 | this._testCases = this._testCases.concat(testCases); 69 | } 70 | return this; 71 | } 72 | 73 | function Test_run(deprecated) { // @ret TestFunctionArray 74 | if (deprecated) { throw new Error("argument error"); } 75 | 76 | var that = this; 77 | var plan = "node_primary > browser_primary > worker_primary > nw_primary > el_primary"; 78 | 79 | if (that._both) { 80 | if (IN_WORKER) { 81 | plan += " > 1000 > swap > node_secondary > browser_secondary"; 82 | } else { 83 | plan += " > 1000 > swap > node_secondary > browser_secondary > worker_secondary"; 84 | } 85 | } 86 | Task.run(plan, { 87 | node_primary: function(task) { _nodeTestRunner(that, task); }, 88 | browser_primary: function(task) { _browserTestRunner(that, task); }, 89 | worker_primary: function(task) { _workerTestRunner(that, task); }, 90 | nw_primary: function(task) { _nwTestRunner(that, task); }, 91 | el_primary: function(task) { _elTestRunner(that, task); }, 92 | swap: function(task) { 93 | _swap(that); 94 | task.pass(); 95 | }, 96 | node_secondary: function(task) { _nodeTestRunner(that, task); }, 97 | browser_secondary: function(task) { _browserTestRunner(that, task); }, 98 | worker_secondary: function(task) { _workerTestRunner(that, task); }, 99 | // nw_secondary: function(task) { _nwTestRunner(that, task); }, 100 | // el_secondary: function(task) { _elTestRunner(that, task); }, 101 | }, function taskFinished(err) { 102 | _undo(that); 103 | // if (err && global["console"]) { 104 | // if (err.stack) { 105 | // console.error(err.stack); 106 | // } else { 107 | // console.error(err.message); 108 | // } 109 | // } 110 | err ? that._errorback(err) : that._callback(); 111 | }); 112 | return this._testCases.slice(); 113 | } 114 | 115 | function _testRunner(that, // @arg this 116 | finishedCallback) { // @arg Function 117 | var testCases = that._testCases.slice(); // clone 118 | var progress = { cur: 0, max: testCases.length }; 119 | var task = new Task(testCases.length, finishedCallback, { "tick": _next }); 120 | 121 | _next(); 122 | 123 | function _next() { 124 | var testCase = testCases.shift(); 125 | if (!testCase) { return; } 126 | 127 | var testCaseName = _getFunctionName(testCase); 128 | if (testCase.length === 0) { 129 | throw new Error("Function " + testCaseName + " has not argument."); 130 | } 131 | var test = { 132 | done: function(error) { 133 | if (IN_BROWSER || IN_NW || IN_EL) { 134 | if (that._button) { 135 | _addTestButton(that, testCase, error ? "red" : "green"); 136 | } 137 | var green = ((++progress.cur / progress.max) * 255) | 0; 138 | var bgcolor = "rgb(0, " + green + ", 0)"; 139 | 140 | document.body["style"]["backgroundColor"] = bgcolor; 141 | } 142 | if (error) { 143 | task.miss(); 144 | } else { 145 | task.pass(); 146 | } 147 | } 148 | }; 149 | var pass = _getPassFunction(that, testCaseName + " pass"); 150 | var miss = _getMissFunction(that, testCaseName + " miss"); 151 | 152 | // textCaseName(test, pass, miss) { 153 | // test.done(pass()); 154 | // test.done(miss()); 155 | // } 156 | 157 | if (!that._ignoreError) { 158 | testCase(test, pass, miss); // execute testCase 159 | } else { 160 | try { 161 | testCase(test, pass, miss); 162 | } catch (o_O) { // [!] catch uncaught exception 163 | miss(); 164 | if (IN_NODE) { 165 | console.log(ERR + testCase + CLR); 166 | } else if (IN_BROWSER || IN_NW) { 167 | global["Help"](testCase, testCaseName); 168 | } 169 | task.message(o_O.message + " in " + testCaseName + " function").miss(); 170 | } 171 | } 172 | } 173 | } 174 | 175 | function _browserTestRunner(that, task) { 176 | if (that._browser) { 177 | if (IN_BROWSER) { 178 | if (document["readyState"] === "complete") { // already document loaded 179 | _onload(that, task); 180 | } else if (global.addEventListener) { // avoid [IE8] error 181 | global.addEventListener("load", function() { _onload(that, task); }); 182 | } else if (global.attachEvent) { 183 | global.attachEvent("onload", function() { _onload(that, task); }); 184 | } 185 | return; 186 | } 187 | } 188 | task.pass(); 189 | } 190 | 191 | function _nwTestRunner(that, task) { 192 | if (that._nw) { 193 | if (IN_NW) { 194 | if (document["readyState"] === "complete") { // already document loaded 195 | _onload(that, task); 196 | } else { 197 | global.addEventListener("load", function() { _onload(that, task); }); 198 | } 199 | return; 200 | } 201 | } 202 | task.pass(); 203 | } 204 | 205 | function _elTestRunner(that, task) { 206 | if (that._el) { 207 | if (IN_EL) { 208 | if (document["readyState"] === "complete") { // already document loaded 209 | _onload(that, task); 210 | } else if (global.addEventListener) { 211 | global.addEventListener("load", function() { _onload(that, task); }); 212 | } 213 | return; 214 | } 215 | } 216 | task.pass(); 217 | } 218 | 219 | function _onload(that, task) { 220 | _testRunner(that, function finishedCallback(err) { 221 | _finishedLog(that, err); 222 | 223 | var n = that._secondary ? 2 : 1; 224 | 225 | document.title = (err ? GHOST : BEER).repeat(n) + document.title; 226 | 227 | //document.body["style"]["backgroundColor"] = err ? "red" : "lime"; 228 | task.done(err); 229 | }); 230 | } 231 | 232 | function _workerTestRunner(that, task) { 233 | if (that._worker) { 234 | if (IN_BROWSER) { 235 | _createWorker(that, task); 236 | return; 237 | } else if (IN_WORKER) { 238 | if (global.unitTest.setting.secondary) { 239 | _swap(that); 240 | } 241 | _testRunner(that, function finishedCallback(err) { 242 | _finishedLog(that, err); 243 | if (err) { 244 | global.unitTest.message = err.message; 245 | } 246 | if (global.unitTest.setting.secondary) { 247 | _undo(that); 248 | } 249 | task.done(err); 250 | }); 251 | return; 252 | } 253 | } 254 | task.pass(); 255 | 256 | function _createWorker(that, task) { 257 | var worker = new Worker("worker.js"); 258 | 259 | worker.onmessage = function(event) { 260 | var message = event.data.message; 261 | 262 | if (message) { 263 | document.body.style.backgroundColor = "red"; // [!] RED screen 264 | console.error("worker.onmessage: " + message); 265 | debugger; 266 | } 267 | task.done(message ? new Error(message) : null); 268 | }; 269 | worker.postMessage({ 270 | message: "", 271 | setting: { 272 | secondary: that._secondary, 273 | baseDir: location.href.split("/").slice(0, -1).join("/") + "/" 274 | }, 275 | }); 276 | } 277 | } 278 | 279 | function _nodeTestRunner(that, task) { 280 | if (that._node) { 281 | if (IN_NODE) { 282 | _testRunner(that, function finishedCallback(err) { 283 | _finishedLog(that, err); 284 | task.done(err); 285 | if (err) { 286 | process.exit(1); // failure ( need Travis-CI ) 287 | } 288 | }); 289 | return; 290 | } 291 | } 292 | task.pass(); 293 | } 294 | 295 | function _swap(that) { 296 | if (that._both) { 297 | if (!that._secondary) { 298 | that._secondary = true; 299 | that._module.forEach(function(moduleName) { 300 | // swap primary <-> secondary module runtime 301 | // [1] keep original runtime to `global.WebModule.moduleName$p$ = primaryModule` 302 | // [2] overwrite module runtime 303 | global["WebModule"][moduleName + "$p$"] = global["WebModule"][moduleName]; // [1] 304 | global["WebModule"][moduleName] = global["WebModule"][moduleName + "_"]; // [2] 305 | if (global["WebModule"]["PUBLISH"]) { // published? 306 | global[moduleName] = global["WebModule"][moduleName + "_"]; // [2] 307 | } 308 | }); 309 | } 310 | } 311 | } 312 | 313 | function _undo(that) { 314 | if (that._both) { 315 | if (that._secondary) { 316 | that._secondary = false; 317 | that._module.forEach(function(moduleName) { 318 | // swap secondary <-> primary module runtime 319 | // [1] return to original runtime 320 | global["WebModule"][moduleName] = global["WebModule"][moduleName + "$p$"]; // [1] 321 | if (global["WebModule"]["PUBLISH"]) { // published? 322 | global[moduleName] = global["WebModule"][moduleName + "$p$"]; // [1] 323 | } 324 | delete global["WebModule"][moduleName + "$p$"]; 325 | }); 326 | } 327 | } 328 | } 329 | 330 | function _getConsoleStyle() { 331 | if (global["console"]) { 332 | return IN_NODE ? "node" 333 | : IN_WORKER ? "worker" 334 | : IN_NW ? "nw" 335 | : IN_EL ? "el" 336 | : STYLISH ? "color" : "browser"; 337 | } 338 | return ""; 339 | } 340 | 341 | function _getPassFunction(that, passMessage) { // @ret PassFunction 342 | var order = that._secondary ? "secondary" : "primary"; 343 | 344 | if (typeof console.log !== "function") { // [IE9] console.log is not function. 345 | return function() { console.log(passMessage); }; 346 | } 347 | 348 | switch ( _getConsoleStyle() ) { 349 | case "node": return console.log.bind(console, INFO + "Node(" + order + "): " + CLR + passMessage); 350 | case "worker": return console.log.bind(console, "Worker(" + order + "): " + passMessage); 351 | case "color": return console.log.bind(console, "%cBrowser(" + order + "): " + passMessage + "%c ", "color:#0c0", ""); 352 | case "browser": return console.log.bind(console, "Browser(" + order + "): " + passMessage); 353 | case "nw": return console.log.bind(console, "nw(" + order + "): " + passMessage); 354 | case "el": return console.log.bind(console, "electron(" + order + "): " + passMessage); 355 | } 356 | return null; 357 | } 358 | 359 | function _getMissFunction(that, missMessage) { // @ret MissFunction 360 | var order = that._secondary ? "secondary" : "primary"; 361 | 362 | switch ( _getConsoleStyle() ) { 363 | case "node": return function() { console.error(ERR +"Node(" + order + "): " + CLR + missMessage); return new Error(); }; 364 | case "worker": return function() { console.error( "Worker(" + order + "): " + missMessage); return new Error(); }; 365 | case "color": return function() { console.error("%cBrowser(" + order + "): " + missMessage + "%c ", "color:#red", ""); return new Error(); }; 366 | case "browser": return function() { console.error( "Browser(" + order + "): " + missMessage); return new Error(); }; 367 | case "nw": return function() { console.error( "nw(" + order + "): " + missMessage); return new Error(); }; 368 | case "el": return function() { console.error( "electron(" + order + "): " + missMessage); return new Error(); }; 369 | } 370 | return null; 371 | } 372 | 373 | function _finishedLog(that, err) { 374 | var n = that._secondary ? 2 : 1; 375 | 376 | if (err) { 377 | _getMissFunction(that, GHOST.repeat(n) + " MISS.")(); 378 | } else { 379 | _getPassFunction(that, BEER.repeat(n) + " PASS ALL.")(); 380 | } 381 | } 382 | 383 | function _addTestButton(that, 384 | testCase, // @arg TestCaseFunction 385 | buttonColor) { // @arg String - button color 386 | // add buttons 387 | var itemName = _getFunctionName(testCase); 388 | var safeName = itemName.replace(/\$/, "_"); // "concat$" -> "concat_" 389 | 390 | if (!document.querySelector("#" + safeName)) { 391 | var inputNode = document.createElement("input"); 392 | var next = "{pass:function(){},miss:function(){},done:function(){}}"; 393 | var pass = "function(){console.log('" + itemName + " pass')}"; 394 | var miss = "function(){console.error('" + itemName + " miss')}"; 395 | var index = that._testCases.indexOf(testCase); 396 | 397 | inputNode.setAttribute("id", safeName); 398 | inputNode.setAttribute("type", "button"); 399 | inputNode.setAttribute("style", "color:" + buttonColor); 400 | inputNode.setAttribute("value", itemName + "()"); 401 | inputNode.setAttribute("onclick", "ModuleTest" + that._module[0] + 402 | "[" + index + "](" + next + ", " + pass + ", " + miss + ")"); 403 | 404 | document.body.appendChild(inputNode); 405 | } 406 | } 407 | 408 | function _getFunctionName(fn) { 409 | return fn["name"] || 410 | (fn + "").split(" ")[1].split("\x28")[0]; // IE 411 | } 412 | 413 | if (!String.prototype.repeat) { 414 | String.prototype.repeat = function(n) { 415 | n = n | 0; 416 | return (this.length && n > 0) ? new Array(n + 1).join(this) : ""; 417 | }; 418 | } 419 | 420 | // --- exports --------------------------------------------- 421 | if (typeof module !== "undefined") { 422 | module["exports"] = Test; 423 | } 424 | global["Test"] = Test; 425 | 426 | })(GLOBAL); 427 | 428 | -------------------------------------------------------------------------------- /lib/Valid.js: -------------------------------------------------------------------------------- 1 | // Valid.js 2 | (function(global) { 3 | "use strict"; 4 | 5 | // --- dependency modules ---------------------------------- 6 | // --- define / local variables ---------------------------- 7 | var TYPED_ARRAYS = [ 8 | "Int8Array", "Uint8Array", "Uint8ClampedArray", 9 | "Int16Array", "Uint16Array", 10 | "Int32Array", "Uint32Array", 11 | "Float32Array", "Float64Array" 12 | ]; 13 | var SPLITTER = /,|\x7c|\x2f/; // Value.keys(value, "a,b|c/d") 14 | var TYPE_SYNONYMS = { 15 | //informal formal 16 | "omit": "Omit", 17 | "null": "Null", 18 | "void": "Undefined", 19 | "Void": "Undefined", 20 | "undefined":"Undefined", 21 | "INTEGER": "Integer", 22 | "INT32": "Int32", 23 | "INT16": "Int16", 24 | "INT8": "Int8", 25 | "UINT32": "Uint32", 26 | "UINT16": "Uint16", 27 | "UINT8": "Uint8", 28 | "percent": "Percent", 29 | }; 30 | var _hook = {}; // { type: callback, ... } 31 | 32 | // --- class / interfaces ---------------------------------- 33 | function Valid(value, // @arg Boolean 34 | api, // @arg Function 35 | highlihgt) { // @arg String = "" 36 | if (!value) { 37 | if (global["Help"]) { 38 | global["Help"](api, highlihgt || ""); 39 | } 40 | throw new Error("Validation Error: " + api["name"] + "(" + highlihgt + ") is invalid value."); 41 | } 42 | } 43 | 44 | Valid["repository"] = "https://github.com/uupaa/Valid.js"; 45 | Valid["args"] = Valid_args; // Valid.args(api:Function, args:Array|ArrayLike):void 46 | Valid["type"] = Valid_type; // Valid.type(value:Any, types:String):Boolean 47 | Valid["some"] = Valid_some; // Valid.some(value:String|null|undefined, candidate:String|Object, ignoreCase:Boolean = false):Boolean 48 | Valid["keys"] = Valid_keys; // Valid.keys(object:Object|Array|null|undefined, key:String):Boolean 49 | Valid["values"] = Valid_values; // Valid.values(object:Object|Array|null|undefined, value:Array):Boolean 50 | Valid["json"] = Valid_json; // Valid.json(json:Object, scheme:Object):Boolean 51 | Valid["stack"] = Valid_stack; // Valid.stack(message:String = "", depth:Integer = 3):String 52 | 53 | // --- extension --- 54 | Valid["register"] = Valid_register; // Valid.register(type:HookTypeString, callback:Function):void 55 | Valid["unregister"] = Valid_unregister; // Valid.unregister(type:HookTypeString):void 56 | Valid["isRegistered"] = Valid_isRegistered; // Valid.isRegistered(type:HookTypeString):Boolean 57 | 58 | // --- implements ------------------------------------------ 59 | function Valid_args(api, // @arg Function 60 | args) { // @arg Array|ArrayLike 61 | if (global["Reflection"]) { 62 | var func = global["Reflection"]["parseFunction"](api); 63 | 64 | //global["Reflection"]["buildFunction"](func); 65 | 66 | func["arg"].forEach(function(item, index) { 67 | var type = item["type"]; 68 | 69 | if (item["optional"]) { 70 | type += "|omit"; 71 | } 72 | if ( !Valid_type(args[index], type) ) { 73 | if (global["Help"]) { 74 | global["Help"](api, item["name"]); 75 | } 76 | throw new Error(api["name"] + "(" + item["name"] + ") is invalid type."); 77 | } 78 | }); 79 | } 80 | } 81 | 82 | function Valid_type(value, // @arg Any 83 | types) { // @arg TypeNameString - "Type1", "Type1|Type2|omit" 84 | // NativeTypeNameString: Array, Number, null ... 85 | // SpecialTypeNameString: Integer, TypedArray, omit ... 86 | // ComplexTypeNameString: URLString, FunctionArray ... 87 | // @ret Boolean 88 | if (arguments.length >= 3) { 89 | throw new Error("The maximum length of Valid.type arguments are 2."); 90 | } 91 | return types.split(SPLITTER).some(_some); 92 | 93 | function _some(type) { // @arg NativeTypeNameString|SpecialTypeNameString|ComplexTypeNameString 94 | // @ret Boolean 95 | type = TYPE_SYNONYMS[type] || type; 96 | 97 | // --- special keywords --- 98 | switch (type) { 99 | case "Any": return true; 100 | case "this": return value instanceof global[_getBaseClassName(value)]; 101 | case "Omit": return value === null || value === undefined; 102 | case "TypedArray": return _isTypedArray(value); 103 | case "Null": return value === null; 104 | case "Undefined": return value === undefined; 105 | case "Array": return Array.isArray(value); 106 | case "Object": return _isObject(value || 0); 107 | case "FunctionArray": 108 | return Array.isArray(value) && _isFunctionArray(value); 109 | case "Percent": return _isNumber(value) && value >= 0.0 && value <= 1.0; 110 | case "Node": return _isNode(value); 111 | case "Error": return _isError(value); 112 | case "Event": return _isEvent(value); 113 | // --- Integer --- 114 | case "Integer": return _isInt(value); 115 | case "Int32": return _isInt(value) && value <= 0x7fffffff && value >= -0x80000000; 116 | case "Int16": return _isInt(value) && value <= 0x7fff && value >= -0x8000; 117 | case "Int8": return _isInt(value) && value <= 0x7f && value >= -0x80; 118 | case "Uint32": return _isUint(value) && value <= 0xffffffff; 119 | case "Uint16": return _isUint(value) && value <= 0xffff; 120 | case "Uint8": return _isUint(value) && value <= 0xff; 121 | // --- Integer Array --- 122 | case "INT32Array": return Array.isArray(value) && value.every(function(v) { return _isInt(v) && v <= 0x7fffffff && v >= -0x80000000; }); 123 | case "INT16Array": return Array.isArray(value) && value.every(function(v) { return _isInt(v) && v <= 0x7fff && v >= -0x8000; }); 124 | case "INT8Array": return Array.isArray(value) && value.every(function(v) { return _isInt(v) && v <= 0x7f && v >= -0x80; }); 125 | case "UINT32Array": return Array.isArray(value) && value.every(function(v) { return _isUint(v) && v <= 0xffffffff; }); 126 | case "UINT16Array": return Array.isArray(value) && value.every(function(v) { return _isUint(v) && v <= 0xffff; }); 127 | case "UINT8Array": return Array.isArray(value) && value.every(function(v) { return _isUint(v) && v <= 0xff; }); 128 | // --- color --- 129 | case "AARRGGBB": 130 | case "RRGGBBAA": return _isUint(value) && value <= 0xffffffff; // Uint32 131 | case "RRGGBB": return _isUint(value) && value <= 0xffffff; // Uint24 132 | // --- postMessage --- 133 | case "TransferableObject": 134 | return _isArrayBuffer(value) || 135 | _isCanvasProxy(value) || 136 | _isMessagePort(value); 137 | case "TransferableObjects": 138 | case "TransferableObjectArray": 139 | return _isTransferableObjects(value); 140 | } 141 | if (value === null || value === undefined) { 142 | return false; 143 | } 144 | 145 | var constructorName = _getConstructorName(value); 146 | var baseClassName = _getBaseClassName(value); 147 | 148 | if (constructorName === type || baseClassName === type) { 149 | return true; 150 | } 151 | if (type in global) { // Is this global Class? 152 | return baseClassName === type; 153 | } 154 | // if (type in global["WebModule"]) { // Is this WebModule Class? 155 | // return baseClassName === type; 156 | // } 157 | 158 | // Valid.register(type) matching 159 | if (type in _hook) { 160 | return _hook[type](type, value); 161 | } 162 | 163 | // greedy complex type matching 164 | // 165 | // "FooIntegerIDString" in global -> false 166 | // "IntegerIDString" in global -> false 167 | // "IDString" in global -> false 168 | // "String" in global -> true 169 | // 170 | var token = _splitComplexTypeName(type); 171 | 172 | if (token.length > 1) { 173 | for (var i = 0, iz = token.length; i < iz; ++i) { 174 | var compositeTypes = token.slice(i).join(""); 175 | 176 | if (compositeTypes in global) { 177 | return _some(compositeTypes); 178 | } 179 | // if (compositeTypes in global["WebModule"]) { 180 | // return _some(compositeTypes); 181 | // } 182 | } 183 | } 184 | return false; 185 | } 186 | 187 | function _isInt(value) { 188 | return _isNumber(value) && Math.ceil(value) === value; 189 | } 190 | function _isUint(value) { 191 | return _isNumber(value) && Math.ceil(value) === value && value >= 0; 192 | } 193 | function _isNode(value) { 194 | return value instanceof Node || _isBaseClass(value, [HTMLElement, Element, Node]); 195 | } 196 | function _isError(value) { 197 | return value instanceof Error || _isBaseClass(value, [Error]); 198 | } 199 | function _isEvent(value) { 200 | return value instanceof Event || _isBaseClass(value, [Event]); 201 | } 202 | function _isBaseClass(value, classArray) { 203 | if (value && "constructor" in value) { 204 | if ("prototype" in value["constructor"]) { 205 | var v = value["constructor"]["prototype"]; 206 | 207 | for (var i = 0, iz = classArray.length; i < iz; ++i) { 208 | if (v instanceof classArray[i]) { 209 | return true; 210 | } 211 | } 212 | } 213 | } 214 | return false; 215 | } 216 | } 217 | 218 | function _splitComplexTypeName(type) { // @arg PascalCaseString - "FooIntegerIDString" 219 | // @ret StringArray - ["Foo", "Integer", "ID", "String"] 220 | var token = []; 221 | 222 | type.replace(/([A-Z]+)[a-z0-9]+/g, function(_, a) { 223 | if (a.length === 1) { 224 | // "String" -> { _: "String", a: "S" } 225 | token.push(_); 226 | } else { 227 | // "IDString" -> { _: "IDString", a: "IDS" } 228 | token.push( _.slice(0, a.length - 1) ); // "ID" 229 | token.push( _.slice(a.length - 1) ); // "String" 230 | } 231 | }); 232 | return token; 233 | } 234 | 235 | function _getBaseClassName(value) { // @arg Any 236 | // @ret String 237 | // Object.prototype.toString.call(new Error()); -> "[object Error]" 238 | // Object.prototype.toString.call(new TypeError()); -> "[object Error]" 239 | return Object.prototype.toString.call(value).split(" ")[1].slice(0, -1); // -> "Error" 240 | } 241 | 242 | function _getConstructorName(value) { // @arg Any - instance, exclude null and undefined. 243 | // @ret String 244 | // _getConstructorName(new (function Aaa() {})); -> "Aaa" 245 | return value.constructor["name"] || 246 | (value.constructor + "").split(" ")[1].split("\x28")[0]; // for IE 247 | } 248 | 249 | function _isTypedArray(value) { // @arg Any 250 | // @ret Boolean 251 | var className = _getBaseClassName(value).toLowerCase(); 252 | 253 | return TYPED_ARRAYS.some(function(typeName) { 254 | return className === typeName.toLowerCase(); 255 | }); 256 | } 257 | 258 | function _isTransferableObjects(value) { // @arg Any 259 | if (Array.isArray(value)) { 260 | return value.some(function(v) { 261 | return _isArrayBuffer(v) || _isCanvasProxy(v) || _isMessagePort(v); 262 | }); 263 | } 264 | return false; 265 | } 266 | function _isArrayBuffer(value) { 267 | if (global["ArrayBuffer"]) { 268 | return value instanceof global["ArrayBuffer"]; 269 | } 270 | return false; 271 | } 272 | function _isCanvasProxy(value) { 273 | if (global["CanvasProxy"]) { 274 | return value instanceof global["CanvasProxy"]; 275 | } 276 | return false; 277 | } 278 | function _isMessagePort(value) { 279 | if (global["MessagePort"]) { 280 | return value instanceof global["MessagePort"]; 281 | } 282 | return false; 283 | } 284 | function _isFunctionArray(value) { 285 | return value.every(function(fn) { 286 | return typeof fn === "function"; 287 | }); 288 | } 289 | 290 | function Valid_some(value, // @arg String|null|undefined - "a" 291 | candidate, // @arg Object|String - "a|b|c" 292 | ignoreCase) { // @arg Boolean = false 293 | // @ret Boolean - true -> has, false -> has not 294 | ignoreCase = ignoreCase || false; 295 | 296 | if (value === null || value === undefined) { 297 | return true; // [!] 298 | } 299 | var keys = _isString(candidate) ? candidate.split(SPLITTER) 300 | : _isObject(candidate) ? Object.keys(candidate) 301 | : []; 302 | 303 | if (ignoreCase) { 304 | value = value.toLowerCase(); 305 | } 306 | return keys.some(function(token) { 307 | if (ignoreCase) { 308 | return value === token.toLowerCase(); 309 | } 310 | return value === token; 311 | }); 312 | } 313 | 314 | function Valid_keys(object, // @arg Object|Array|null|undefined - { a: 1, b: 2 } 315 | key) { // @arg String - valid choices. "a|b" 316 | // @ret Boolean - false is unmatched object. 317 | if (object === null || object === undefined) { 318 | return true; // [!] 319 | } 320 | if (_isObject(object) || // Valid.keys({a:0,b:1}, "a|b") 321 | Array.isArray(object)) { // Valid.keys([9,9], "0|1") 322 | 323 | var list = _split(key); 324 | 325 | return Object.keys(object).every(function(objectKey) { 326 | return list.indexOf(objectKey) >= 0; 327 | }); 328 | } 329 | return false; 330 | } 331 | 332 | function Valid_values(object, // @arg Object|Array|null|undefined - { a: 1, b: 2 } 333 | value) { // @arg Array - valid choices. [1, 2] 334 | // @ret Boolean - false is unmatched object. 335 | if (object === null || object === undefined) { 336 | return true; // [!] 337 | } 338 | if (_isObject(object) || // Valid.values({a:0,b:1}, [0,1]) 339 | Array.isArray(object)) { // Valid.values([9,9], [9,9]) 340 | 341 | return Object_values(object).every(function(objectValue) { 342 | return value.indexOf(objectValue) >= 0; 343 | }); 344 | } 345 | return false; 346 | } 347 | 348 | function Valid_some(value, // @arg String|null|undefined - "a" 349 | candidate, // @arg String|Object - "a|b|c", { 1: "a", 2: "b" }, ["a", "b"] 350 | ignoreCase) { // @arg Boolean = false 351 | // @ret Boolean - true -> has, false -> has not 352 | // Valid.some("foo", "foo|bar"); -> true 353 | // Valid.some("foo", { foo:1, bar: 2 }); -> true 354 | ignoreCase = ignoreCase || false; 355 | 356 | if (value === null || value === undefined) { 357 | return true; // [!] 358 | } 359 | var keys = _isString(candidate) ? candidate.split(SPLITTER) 360 | : _isObject(candidate) ? Object.keys(candidate) 361 | : []; 362 | 363 | if (ignoreCase) { 364 | value = value.toLowerCase(); 365 | } 366 | return keys.some(function(token) { 367 | if (ignoreCase) { 368 | return value === token.toLowerCase(); 369 | } 370 | return value === token; 371 | }); 372 | } 373 | 374 | function Valid_json(json, // @arg JSONObject 375 | scheme) { // @arg JSONObject 376 | // @ret Boolean - false is invalid. 377 | var rv = _json(json, scheme, ""); 378 | 379 | if (rv) { 380 | return true; 381 | } 382 | console.log("json: " + JSON.stringify(json, null, 2)); 383 | console.log("scheme: " + JSON.stringify(scheme, null, 2)); 384 | return false; 385 | } 386 | 387 | function _json(json, scheme, path) { 388 | path = path || ""; 389 | return Object.keys(scheme).every(function(schemeKey) { 390 | var schemeType = Object.prototype.toString.call(scheme[schemeKey]).slice(8, -1); 391 | 392 | if (schemeKey in json) { 393 | if ( !Valid_type(json[schemeKey], schemeType) ) { 394 | console.error("Valid.json type missmatch: " + path + schemeKey + " is not " + schemeType); 395 | return false; 396 | } else if (schemeType === "Object" || schemeType === "Array") { 397 | return _json(json[schemeKey], scheme[schemeKey], path + schemeKey + "."); 398 | } 399 | return true; 400 | } 401 | console.error("Valid.json unknown property: " + path + schemeKey); 402 | return false; 403 | }); 404 | } 405 | 406 | function Valid_stack(message, // @arg String = "" 407 | depth) { // @arg Integer = 3 408 | depth = depth || 3; 409 | var rv = ""; 410 | 411 | try { 412 | throw new Error(); 413 | } catch (o_o) { 414 | rv = (message || "") + "\n" + 415 | o_o.stack.split("\n").slice(depth).join("\n"); 416 | } 417 | return rv; 418 | } 419 | 420 | function Valid_register(type, // @arg HookTypeString 421 | callback) { // @arg Function - callback(type, value):Boolean 422 | _hook[type] = callback; 423 | } 424 | 425 | function Valid_unregister(type) { // @arg HookTypeString 426 | delete _hook[type]; 427 | } 428 | 429 | function Valid_isRegistered(type) { // @arg HookTypeString 430 | // @ret Boolean 431 | return type in _hook; 432 | } 433 | 434 | function _isObject(object) { // @arg Object|Any 435 | // @ret Boolean 436 | return object.constructor === ({}).constructor; 437 | } 438 | 439 | function _isNumber(object) { // @arg Number|Any 440 | // @ret Boolean 441 | return typeof object === "number"; 442 | } 443 | 444 | function _isString(object) { // @arg String|Any 445 | // @ret Boolean 446 | return typeof object === "string"; 447 | } 448 | 449 | function _split(keywords) { // @arg String 450 | return keywords.replace(/ /g, "").split(SPLITTER); 451 | } 452 | 453 | // ES2016 function. copy from ES.js 454 | function Object_values(source) { // @arg Object|Function|Array 455 | // @ret ValueAnyArray [key, ... ] 456 | 457 | var keys = Object.keys(source); 458 | var i = 0, iz = keys.length; 459 | var result = new Array(iz); 460 | 461 | for (; i < iz; ++i) { 462 | result[i] = source[keys[i]]; 463 | } 464 | return result; 465 | } 466 | 467 | // --- exports --------------------------------------------- 468 | if (typeof module !== "undefined") { 469 | module["exports"] = Valid; 470 | } 471 | global["Valid"] = Valid; 472 | 473 | })(GLOBAL); 474 | 475 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webmodule", 3 | "version": "0.7.10", 4 | "description": "Generate a JavaScript based module for Mobile Web Application.", 5 | "url": "https://github.com/uupaa/WebModule", 6 | "keywords": ["uupaa", "WebModule"], 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/uupaa/WebModule.js.git" 10 | }, 11 | "dependencies": { 12 | }, 13 | "devDependencies": { 14 | }, 15 | "author": "uupaa ", 16 | "license": "MIT", 17 | "contributors": [] 18 | } 19 | -------------------------------------------------------------------------------- /run/add-src.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | (function(global) { 4 | 5 | // Usage: WebModule/run/add-src.js NewClass.js 6 | 7 | var ERR = "\u001b[31m"; 8 | var WARN = "\u001b[33m"; 9 | var INFO = "\u001b[32m"; 10 | var CLR = "\u001b[0m"; 11 | 12 | var fs = require("fs"); 13 | var argv = process.argv.slice(2); 14 | var srcName = argv[0]; // "NewClass.js" 15 | var className= argv[0].replace(/\.js$/, ""); // "NewClass" 16 | 17 | var BASE_MODEL_DIR = "BASE_MODEL/"; 18 | var sourceDir = process.argv[1].split("/").slice(0, -2).join("/") + "/"; 19 | var targetDir = process.cwd() + "/"; 20 | var targetPackageJSON = require(targetDir + "package.json"); 21 | var GITHUB_USER_NAME = targetPackageJSON.repository.url.split("/")[3]; 22 | var sourceCode = fs.readFileSync(sourceDir + BASE_MODEL_DIR + "/lib/REPOSITORY_NAME.js", "UTF-8"); 23 | var targetPath = targetDir + "lib/" + srcName; 24 | 25 | 26 | if ( !/\.js$/.test(srcName) ) { 27 | console.log(ERR + " The file name must have .js extension. " + CLR); 28 | return; 29 | } 30 | if ( fs.existsSync(targetPath) ) { 31 | console.log(ERR + " The file already exists. " + CLR + targetPath); 32 | return; 33 | } 34 | fs.writeFileSync(targetPath, _repleaceText(sourceCode), "utf-8"); 35 | 36 | console.log(INFO + " Add source: " + targetPath + CLR); 37 | 38 | // ------------------------------------------------------------- 39 | function _repleaceText(text) { 40 | text = text.replace(/<>/g, GITHUB_USER_NAME); // "uupaa" 41 | text = text.replace(/<>/g, className); // "Foo" 42 | text = text.replace(/__19_SPACE_________/g, _spacer(className.length)); // "Foo" 43 | 44 | return text; 45 | } 46 | 47 | function _spacer(n) { // @arg Integer 48 | // @ret String 49 | return " ".slice(0, n); 50 | } 51 | 52 | })(GLOBAL); 53 | 54 | -------------------------------------------------------------------------------- /run/add-subclass.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | (function(global) { 4 | 5 | // Usage: WebModule/run/add-subclass.js SubClass.js BaseClass 6 | 7 | var ERR = "\u001b[31m"; 8 | var WARN = "\u001b[33m"; 9 | var INFO = "\u001b[32m"; 10 | var CLR = "\u001b[0m"; 11 | 12 | var fs = require("fs"); 13 | var argv = process.argv.slice(2); 14 | var srcName = argv[0]; // "SubClass.js" 15 | var subClass = argv[0].replace(/\.js$/, ""); // "SubClass" 16 | var baseClass= argv[1].replace(/\.js$/, ""); // "BaseClass" 17 | 18 | var BASE_MODEL_DIR = "BASE_MODEL/"; 19 | var sourceDir = process.argv[1].split("/").slice(0, -2).join("/") + "/"; 20 | var targetDir = process.cwd() + "/"; 21 | var targetPackageJSON = require(targetDir + "package.json"); 22 | var GITHUB_USER_NAME = targetPackageJSON.repository.url.split("/")[3]; 23 | var sourceCode = fs.readFileSync(sourceDir + BASE_MODEL_DIR + "/lib/SUB_CLASS.js", "UTF-8"); 24 | var targetPath = targetDir + "lib/" + srcName; 25 | 26 | 27 | if ( !/\.js$/.test(srcName) ) { 28 | console.log(ERR + " The file name must have .js extension. " + CLR); 29 | return; 30 | } 31 | if ( !baseClass) { 32 | console.log(ERR + " Need BaseClass name " + CLR); 33 | return; 34 | } 35 | if ( fs.existsSync(targetPath) ) { 36 | console.log(ERR + " The file already exists. " + CLR + targetPath); 37 | return; 38 | } 39 | fs.writeFileSync(targetPath, _repleaceText(sourceCode), "utf-8"); 40 | 41 | console.log(INFO + " Add source: " + targetPath + CLR); 42 | 43 | // ------------------------------------------------------------- 44 | function _repleaceText(text) { 45 | text = text.replace(/<>/g, baseClass); 46 | text = text.replace(/<>/g, subClass); 47 | text = text.replace(/__19_SPACE_________/g, _spacer(subClass.length)); 48 | 49 | return text; 50 | } 51 | 52 | function _spacer(n) { // @arg Integer 53 | // @ret String 54 | return " ".slice(0, n); 55 | } 56 | 57 | })(GLOBAL); 58 | 59 | -------------------------------------------------------------------------------- /run/es6to5.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | (function(global) { 4 | 5 | // alt/ ディレクトリ以下のファイルを検索し、 6 | // 各ファイルを個別に es6 から es5 にダウンコンパイルした結果を lib/ 以下に出力します 7 | 8 | // --- console colors --- 9 | var ERR = "\u001b[31m"; // RED 10 | var WARN = "\u001b[33m"; // YELLOW 11 | var INFO = "\u001b[32m"; // GREEN 12 | var CLR = "\u001b[0m"; // WHITE 13 | var LB = "\n"; // line break 14 | 15 | var fs = require("fs"); 16 | var cp = require("child_process"); 17 | var readline = require("readline"); 18 | var wmlib = process.argv[1].split("/").slice(0, -2).join("/") + "/lib/"; // "WebModule/lib/" 19 | var mod = require(wmlib + "ModuleSystem.js"); 20 | var Task = require(wmlib + "Task.js"); 21 | var argv = process.argv.slice(2); 22 | 23 | var repositoryFullName = process.cwd().split("/").pop(); 24 | var repositoryName = repositoryFullName.indexOf(".") >= 0 25 | ? repositoryFullName.split(".").slice(0, -1).join(".") 26 | : repositoryFullName; 27 | 28 | var sourceDir = process.argv[1].split("/").slice(0, -2).join("/") + "/"; 29 | var targetDir = process.cwd() + "/"; 30 | var sourcePacakgeJSON = sourceDir + "MODULE_package.json"; 31 | var targetPackageJSON = targetDir + "package.json"; 32 | 33 | console.log( INFO + " - repositoryFullName: " + repositoryFullName + CLR ); // "Foo.js" 34 | console.log( INFO + " - repositoryName: " + repositoryName + CLR ); // "Foo" 35 | console.log( INFO + " - copy source dir: " + sourceDir + CLR ); // "/Users/uupaa/oss/WebModule/" 36 | console.log( INFO + " - copy target dir: " + targetDir + CLR ); // "/Users/uupaa/oss/Foo.js/" 37 | console.log( INFO + " - source package.json: " + sourcePacakgeJSON + CLR ); // "/Users/uupaa/oss/my/WebModule/MODULE_package.json" 38 | console.log( INFO + " - target package.json: " + targetPackageJSON + CLR + LB ); // "/Users/uupaa/oss/my/Foo.js/package.json" 39 | 40 | // TODO: impl 41 | 42 | })(GLOBAL); 43 | 44 | -------------------------------------------------------------------------------- /run/minify.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | (function(global) { 4 | 5 | var USAGE = _multiline(function() {/* 6 | Usage: 7 | node Minify.js [@label ...] 8 | [--help] 9 | [--verbose] 10 | [--nowrap] 11 | [--header file] 12 | [--footer file] 13 | [--es5in] 14 | [--es6in] 15 | [--es5out] 16 | [--es6out] 17 | [--keep] 18 | [--pretty] 19 | [--option "compile option"] 20 | [--extern file] 21 | [--label @label] 22 | [--optimize num] 23 | [--include_modules] 24 | 25 | [--release] -> optimize=3 26 | 27 | See: 28 | https://github.com/uupaa/Minify.js/wiki/Minify 29 | */}); 30 | 31 | var ERR = "\u001b[31m"; // RED 32 | var WARN = "\u001b[33m"; // YELLOW 33 | var INFO = "\u001b[32m"; // GREEN 34 | var CLR = "\u001b[0m"; // WHITE 35 | 36 | var fs = require("fs"); 37 | var cp = require("child_process"); 38 | var argv = process.argv.slice(2); 39 | var wmlib = process.argv[1].split("/").slice(0, -2).join("/") + "/lib/"; // "WebModule/lib/" 40 | var mod = require(wmlib + "ModuleSystem.js"); 41 | var pkg = JSON.parse(fs.readFileSync("./package.json", "utf8")); 42 | var wm = pkg.webmodule; 43 | var Task = require(wmlib + "Task.js"); 44 | var target = mod.collectBuildTarget(pkg); 45 | 46 | var options = _parseCommandLineOptions({ 47 | name: pkg.name, // Object - { git:String, npm:String }. github repository name, npm package name. 48 | help: false, // Boolean - true is show help. 49 | keep: false, // Boolean - keep tmp file. 50 | label: ["dev", "debug", "assert"], // LabelStringArray 51 | nowrap: false, // Boolean - false -> wrap WebModule idiom. 52 | header: "", // PathString - header file. 53 | footer: "", // PathString - footer file. 54 | es5in: false, // Boolean - input ES5 code. 55 | es6in: false, // Boolean - input ES6 code. 56 | es5out: false, // Boolean - output ES5 code. 57 | es6out: false, // Boolean - output ES6 code. 58 | strict: true, // Boolean - true -> add 'use strict'. 59 | pretty: false, // Boolean - true -> pretty print. 60 | option: [], // OptionStringArray - ["language_in ECMASCRIPT5_STRICT", ...] 61 | optimize: 1, // Number - 0 -> Concat, 1 -> WhiteSpace, 2 -> Simple, 3 -> Advanced 62 | externs: [], // FilePathArray- ["externs-file-name", ...] 63 | verbose: false, // Boolean - true -> verbose mode. 64 | workDir: "release/", // PathString - work dir. 65 | include_modules: false, // Boolean - true -> include npm_modules. use NodeModule.files(). 66 | }); 67 | 68 | if (options.help) { 69 | console.log(WARN + USAGE + CLR); 70 | return; 71 | } 72 | 73 | // --- detect work dir --- 74 | if (!target.workDir) { 75 | console.log(ERR + "package.json - webmodule.{browser|worker|node}.output are empty." + CLR); 76 | return; 77 | } 78 | 79 | var browserSource = target.browser.source; 80 | var workerSource = target.worker.source; 81 | var nodeSource = target.node.source; 82 | var nwSource = target.nw.source; 83 | var elSource = target.el.source; 84 | 85 | if (options.include_modules) { 86 | // 依存関係にあるソース(deps.files.{browser|worker|node|nw|el})を取得する 87 | var deps = mod.getDependencies(true); 88 | 89 | // コードをマージし重複を取り除く 90 | browserSource = mod.toUniqueArray([].concat(deps.files.browser, browserSource)); 91 | workerSource = mod.toUniqueArray([].concat(deps.files.worker, workerSource)); 92 | nodeSource = mod.toUniqueArray([].concat(deps.files.node, nodeSource)); 93 | nwSource = mod.toUniqueArray([].concat(deps.files.nw, nwSource)); 94 | elSource = mod.toUniqueArray([].concat(deps.files.el, elSource)); 95 | 96 | if (options.verbose) { 97 | var buildFiles = { 98 | "browser": browserSource, 99 | "worker": workerSource, 100 | "node": nodeSource, 101 | "nw": nwSource, 102 | "el": elSource, 103 | "label": deps.files.label 104 | }; 105 | console.log(INFO + "Include node_modules: " + JSON.stringify(buildFiles, null, 2) + CLR); 106 | } 107 | } 108 | 109 | if (!_isFileExists(options.externs) || 110 | !_isFileExists(browserSource) || 111 | !_isFileExists(workerSource) || 112 | !_isFileExists(nodeSource) || 113 | !_isFileExists(nwSource) || 114 | !_isFileExists(elSource)) { 115 | return; 116 | } 117 | 118 | var minifyOptions = { 119 | "keep": options.keep, 120 | "label": options.label, 121 | "nowrap": options.nowrap, 122 | "header": options.header, 123 | "footer": options.footer, 124 | "es5in": options.es5in, 125 | "es6in": options.es6in, 126 | "es5out": options.es5out, 127 | "es6out": options.es6out, 128 | "strict": options.strict, 129 | "pretty": options.pretty, 130 | "option": options.option, 131 | "externs": options.externs, 132 | "verbose": options.verbose, 133 | "workDir": options.workDir, 134 | "optimize": options.optimize, 135 | }; 136 | 137 | // --- コンパイル対象を決定する --- 138 | // できるだけ無駄なコンパイルは避ける 139 | // コンパイル対象のソースコードがbrowser,worker,node,nw,el の全てで同じ場合は一度だけ(browserだけを)コンパイルする 140 | // - browser,worker,node,nw,el が全て異なる場合は、それぞれの環境に向けて特殊化したビルドを行う。4回ビルドすることになる 141 | // - browserとworkerが同じ場合は、browser用のファイルをworkerにコピーする 142 | // - browserとnodeが同じ場合は、browser用のファイルをnodeにコピーする 143 | // - browserとnwが同じ場合は、browser用のファイルをnwにコピーする 144 | // - browserとelが同じ場合は、browser用のファイルをelにコピーする 145 | // - workerとnodeが同じ場合は、worker用のファイルをnodeにコピーする 146 | var taskPlan = []; 147 | var copyBrowserFileToWorkerFile = false; // browser用のビルドをコピーしworkerとしても使用する 148 | var copyBrowserFileToNodeFile = false; // browser用のビルドをコピーしnodeとしても使用する 149 | var copyBrowserFileToNWFile = false; // browser用のビルドをコピーしnwとしても使用する 150 | var copyBrowserFileToELFile = false; // browser用のビルドをコピーしelとしても使用する 151 | var copyWorkerFileToNodeFile = false; // worker用のビルドをコピーしnodeとしても使用する 152 | 153 | if (wm.browser && browserSource.length) { taskPlan.push("browser"); } 154 | if (wm.worker && workerSource.length) { taskPlan.push("worker"); } 155 | if (wm.node && nodeSource.length) { taskPlan.push("node"); } 156 | if (wm.nw && nwSource.length) { taskPlan.push("nw"); } 157 | if (wm.el && elSource.length) { taskPlan.push("el"); } 158 | 159 | // browserとworkerのファイル構成が一緒の場合はまとめてしまい、workerのビルドを省略する 160 | if (taskPlan.indexOf("browser") >= 0 && taskPlan.indexOf("worker") >= 0) { 161 | if (browserSource.join() === workerSource.join()) { 162 | copyBrowserFileToWorkerFile = true; 163 | taskPlan = taskPlan.filter(function(target) { return target !== "worker"; }); 164 | } 165 | } 166 | // browserとnodeのファイル構成が一緒の場合はまとめてしまい、nodeのビルドを省略する 167 | if (taskPlan.indexOf("browser") >= 0 && taskPlan.indexOf("node") >= 0) { 168 | if (browserSource.join() === nodeSource.join()) { 169 | copyBrowserFileToNodeFile = true; 170 | taskPlan = taskPlan.filter(function(target) { return target !== "node"; }); 171 | } 172 | } 173 | // browserとnwのファイル構成が一緒の場合はまとめてしまい、nwのビルドを省略する 174 | if (taskPlan.indexOf("browser") >= 0 && taskPlan.indexOf("nw") >= 0) { 175 | if (browserSource.join() === nwSource.join()) { 176 | copyBrowserFileToNWFile = true; 177 | taskPlan = taskPlan.filter(function(target) { return target !== "nw"; }); 178 | } 179 | } 180 | // browserとelのファイル構成が一緒の場合はまとめてしまい、elのビルドを省略する 181 | if (taskPlan.indexOf("browser") >= 0 && taskPlan.indexOf("el") >= 0) { 182 | if (browserSource.join() === elSource.join()) { 183 | copyBrowserFileToELFile = true; 184 | taskPlan = taskPlan.filter(function(target) { return target !== "el"; }); 185 | } 186 | } 187 | // workerとnodeのファイル構成が一緒の場合はまとめてしまい、nodeのビルドを省略する 188 | if (taskPlan.indexOf("worker") >= 0 && taskPlan.indexOf("node") >= 0) { 189 | if (workerSource.join() === nodeSource.join()) { 190 | copyWorkerFileToNodeFile = true; 191 | taskPlan = taskPlan.filter(function(target) { return target !== "node"; }); 192 | } 193 | } 194 | 195 | Task.run(taskPlan.join(" > "), { 196 | "browser": function(task) { 197 | if (options.verbose) { 198 | console.log("Build for the browser..."); 199 | } 200 | Minify(browserSource, minifyOptions, function(err, js) { 201 | if (err || !js) { 202 | task.miss(); 203 | } else { 204 | fs.writeFileSync(target.browser.output, js); 205 | if (copyBrowserFileToWorkerFile) { 206 | fs.writeFileSync(target.worker.output, js); 207 | } 208 | if (copyBrowserFileToNodeFile) { 209 | fs.writeFileSync(target.node.output, js); 210 | } 211 | if (copyBrowserFileToNWFile) { 212 | fs.writeFileSync(target.nw.output, js); 213 | } 214 | if (copyBrowserFileToELFile) { 215 | fs.writeFileSync(target.el.output, js); 216 | } 217 | task.pass(); 218 | } 219 | }); 220 | }, 221 | "worker": function(task) { 222 | if (options.verbose) { 223 | console.log("Build for the worker..."); 224 | } 225 | Minify(workerSource, minifyOptions, function(err, js) { 226 | if (err || !js) { 227 | task.miss(); 228 | } else { 229 | fs.writeFileSync(target.worker.output, js); 230 | if (copyWorkerFileToNodeFile) { 231 | fs.writeFileSync(target.node.output, js); 232 | } 233 | task.pass(); 234 | } 235 | }); 236 | }, 237 | "node": function(task) { 238 | if (options.verbose) { 239 | console.log("Build for the node..."); 240 | } 241 | Minify(nodeSource, minifyOptions, function(err, js) { 242 | if (err || !js) { 243 | task.miss(); 244 | } else { 245 | fs.writeFileSync(target.node.output, js); 246 | task.pass(); 247 | } 248 | }); 249 | }, 250 | "nw": function(task) { 251 | if (options.verbose) { 252 | console.log("Build for the nw..."); 253 | } 254 | Minify(nwSource, minifyOptions, function(err, js) { 255 | if (err || !js) { 256 | task.miss(); 257 | } else { 258 | fs.writeFileSync(target.nw.output, js); 259 | task.pass(); 260 | } 261 | }); 262 | }, 263 | "el": function(task) { 264 | if (options.verbose) { 265 | console.log("Build for the electron..."); 266 | } 267 | Minify(elSource, minifyOptions, function(err, js) { 268 | if (err || !js) { 269 | task.miss(); 270 | } else { 271 | fs.writeFileSync(target.el.output, js); 272 | task.pass(); 273 | } 274 | }); 275 | } 276 | }, function(err) { 277 | if (err) { 278 | if (options.verbose) { 279 | console.log(ERR + "Build error." + CLR); 280 | process.exit(1); 281 | } 282 | } else { 283 | if (options.verbose) { 284 | console.log("done."); 285 | } 286 | } 287 | }); 288 | 289 | function _isFileExists(fileList) { // @arg Array 290 | // @ret Boolean 291 | return fileList.every(function(file) { 292 | if (!fs.existsSync(file)) { 293 | console.log(ERR + "File not found: " + file + CLR); 294 | return false; 295 | } 296 | return true; 297 | }); 298 | } 299 | 300 | function _parseCommandLineOptions(options) { 301 | for (var i = 0, iz = argv.length; i < iz; ++i) { 302 | switch (argv[i]) { 303 | case "-h": 304 | case "--help": options.help = true; break; 305 | case "-v": 306 | case "--verbose": options.verbose = true; break; 307 | case "--nowrap": options.nowrap = true; break; 308 | case "--header": options.header = fs.readFileSync(argv[++i], "utf8"); break; 309 | case "--footer": options.footer = fs.readFileSync(argv[++i], "utf8"); break; 310 | case "--es5in": options.es5in = true; break; 311 | case "--es6in": options.es6in = true; break; 312 | case "--es5out": options.es5out = true; break; 313 | case "--es6out": options.es6out = true; break; 314 | case "--strict": break; // [DEPRECATED] 315 | case "--keep": options.keep = true; break; 316 | case "--simple": break; // [DEPRECATED] 317 | case "--extern": 318 | case "--externs": _pushif(options.externs, argv[++i]); break; 319 | case "--option": _pushif(options.option, argv[++i]); break; 320 | case "--pretty": options.pretty = true; break; 321 | case "--optimize": _pushif(options.externs, argv[++i]); break; 322 | case "--concat": options.optimize = 0; 323 | options.include_modules = true; break; 324 | case "--debug": options.optimize = 1; 325 | options.include_modules = true; break; 326 | case "--release": options.optimize = 3; 327 | options.include_modules = true; break; 328 | case "--label": _pushif(options.label, argv[++i].replace(/^@/, "")); break; 329 | case "--include_modules": options.include_modules = true; break; 330 | default: 331 | if ( /^@/.test(argv[i]) ) { // @label 332 | _pushif(options.label, argv[i].replace(/^@/, "")); 333 | } else { 334 | throw new Error("Unknown option: " + argv[i]); 335 | } 336 | } 337 | } 338 | return options; 339 | } 340 | 341 | function _pushif(source, value) { 342 | if (source.indexOf(value) < 0) { // avoid duplicate 343 | source.push(value); 344 | } 345 | } 346 | 347 | function _multiline(fn) { // @arg Function 348 | // @ret String 349 | return (fn + "").split("\n").slice(1, -1).join("\n"); 350 | } 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | // Closure Compiler Service 367 | // http://closure-compiler.appspot.com/home 368 | 369 | // --- dependency modules ---------------------------------- 370 | 371 | // --- define / local variables ---------------------------- 372 | //var _runOnNode = "process" in global; 373 | //var _runOnWorker = "WorkerLocation" in global; 374 | //var _runOnBrowser = "document" in global; 375 | 376 | var OUTPUT_FILE = "./.Minify.output.js"; 377 | var TMP_FILE = "./.Minify.tmp.js"; 378 | 379 | // --- class / interfaces ---------------------------------- 380 | function Minify(sources, // @arg StringArray - JavaScript sources file path. [path, ...] 381 | options, // @arg Object = null - { keep, label, nowrap, header, footer, es5in, es6in, es5out, es6out, strict, pretty, option, externs, verbose, workDir, optimize } 382 | // @options.keep Boolean = false - keep temporary file. 383 | // @options.label LabelStringArray = null - ["@label", ...] 384 | // @options.nowrap Boolean = false - false is wrap WebModule idiom. 385 | // @options.header String = "" - Header part extras JavaScript expression string. 386 | // @options.footer String = "" - Footer part extras JavaScript expression string. 387 | // @options.es5in Boolean = false - input ES5 code. 388 | // @options.es6in Boolean = false - input ES6 code. 389 | // @options.es5out Boolean = false - output ES5 code. 390 | // @options.es6out Boolean = false - output ES6 code. 391 | // @options.strict Boolean = false - true is add 'use strict'. 392 | // @options.pretty Boolean = false - true is pretty strict. 393 | // @options.option StringArray = [] - ClosureCompiler additional options string. 394 | // @options.externs StringArray = [] - Clouser Compiler externs definition file path 395 | // @options.verbose boolean = false - true is verbose mode. 396 | // @options.workDir String = "" - work dir. 397 | // @options.optimize Number = 0 - 0 = Concat, 1 = WhiteSpace, 2 = Simple, 3 = Advanced 398 | fn) { // @arg Function = null - callback function. fn(err:Error, result:String) 399 | //{@dev 400 | _if(!Array.isArray(sources), Minify, "sources"); 401 | if (options) { 402 | _if(options.constructor !== ({}).constructor, Minify, "options"); 403 | _if(!_keys(options, "keep,label,nowrap,header,footer,es5in,es6in,es5out,es6out,strict,pretty,option,externs,verbose,workDir,optimize"), Minify, "options"); 404 | } 405 | if (fn) { 406 | _if(typeof fn !== "function", Minify, "fn"); 407 | } 408 | //}@dev 409 | 410 | 411 | if (options.optimize > 0) { 412 | var optionsString = _makeClouserCompilerOptions(options); 413 | 414 | cp.exec("which -s closure-compiler", function(err) { 415 | // $ node install uupaa.compile.js 416 | _offlineMinificationNode(sources, options, optionsString, fn); 417 | }); 418 | } else { 419 | // debug build, concat and preprocess only. 420 | _noMinification(sources, options, fn); 421 | } 422 | } 423 | 424 | // --- implements ------------------------------------------ 425 | function _makeClouserCompilerOptions(options) { // @arg Object - { keep, nowrap, ... }. see Minify() 426 | // @ret String - "--option value ..." 427 | var result = []; 428 | 429 | //result["transform_amd_modules"] = ""; 430 | //result["create_source_map"] = "source.map"; 431 | 432 | switch (options.optimize) { 433 | case 3: 434 | result.push("--compilation_level ADVANCED_OPTIMIZATIONS"); 435 | if (options.externs && options.externs.length) { 436 | result.push("--externs " + options.externs.join(" --externs ")); 437 | } 438 | break; 439 | case 2: 440 | result.push("--compilation_level SIMPLE_OPTIMIZATIONS"); 441 | break; 442 | case 1: 443 | result.push("--compilation_level WHITESPACE_ONLY"); 444 | break; 445 | } 446 | if (!options.nowrap) { // wrap WebModule idiom 447 | //result.push("--output_wrapper '(function(global){\n%output%\n})((this||0).self||global);'"); 448 | result.push("--output_wrapper '(function(global){\n%output%\n})(GLOBAL);'"); // WebModule Idiom v2 449 | } 450 | 451 | if (options.strict) { 452 | if (options.es5in) { 453 | result.push("--language_in ECMASCRIPT5_STRICT"); 454 | } else if (options.es6in) { 455 | result.push("--language_in ECMASCRIPT6_STRICT"); 456 | } else { // back compat 457 | result.push("--language_in ECMASCRIPT5_STRICT"); 458 | } 459 | if (options.es5out) { 460 | result.push("--language_out ECMASCRIPT5_STRICT"); 461 | } else if (options.es6out) { 462 | result.push("--language_out ECMASCRIPT6_STRICT"); 463 | } 464 | } else { 465 | if (options.es5in) { 466 | result.push("--language_in ECMASCRIPT5"); 467 | } else if (options.es6in) { 468 | result.push("--language_in ECMASCRIPT6"); 469 | } else { // back compat 470 | result.push("--language_in ECMASCRIPT5"); 471 | } 472 | if (options.es5out) { 473 | result.push("--language_out ECMASCRIPT5"); 474 | } else if (options.es6out) { 475 | result.push("--language_out ECMASCRIPT6"); 476 | } 477 | } 478 | if (options.pretty) { 479 | result.push("--formatting pretty_print"); 480 | } 481 | if (options.option.length) { 482 | result.push("--" + optionsObject.option.join(" --")); 483 | } 484 | return result.join(" "); 485 | } 486 | 487 | function _offlineMinificationNode(sources, // @arg StringArray - JavaScript SourceCode file path. [path, ...] 488 | options, // @arg Object - { keep, nowrap, ... }. see Minify() 489 | optionsString, // @arg String 490 | callback) { // @arg Function = null - callback(err:Error, result:String) 491 | 492 | var js = (options.header || "") + _concatFiles(sources) + (options.footer || ""); 493 | 494 | if (options.label && options.label.length) { 495 | js = Minify_preprocess(js, options.label); 496 | } 497 | fs.writeFileSync(options.workDir + TMP_FILE, js); 498 | 499 | if (options.verbose) { 500 | console.log(INFO + "Compile options: \n " + optionsString.replace(/\n/g, "") + CLR); 501 | } 502 | 503 | // `npm install -g uupaa.compile.js` 504 | var compile = require("uupaa.compile.js"); 505 | 506 | compile.exec(options.workDir + TMP_FILE, 507 | options.workDir + OUTPUT_FILE, 508 | optionsString, 509 | function(err, stdout, stderr) { 510 | if (err || stderr) { 511 | console.log(stderr); 512 | if (callback) { 513 | callback(new Error(stderr), ""); 514 | } 515 | } else { 516 | var minifiedCode = fs.readFileSync(options.workDir + OUTPUT_FILE, "utf8"); 517 | 518 | fs.unlinkSync(options.workDir + OUTPUT_FILE); 519 | if (!options.keep) { 520 | fs.unlinkSync(options.workDir + TMP_FILE); 521 | } 522 | if (callback) { 523 | callback(null, minifiedCode); 524 | } 525 | } 526 | }); 527 | } 528 | 529 | function Minify_preprocess(js, // @arg String - JavaScript expression string. 530 | labels) { // @arg StringArray - strip labels. ["label", ...] 531 | //{@dev 532 | _if(typeof js !== "string", Minify_preprocess, "js"); 533 | _if(!Array.isArray(labels), Minify_preprocess, "labels"); 534 | //}@dev 535 | 536 | // normalize line feed. 537 | js = js.replace(/(\r\n|\r|\n)/mg, "\n"); 538 | 539 | // trim code block. 540 | js = _trimCodeBlock(js, labels); 541 | 542 | return js; 543 | } 544 | 545 | function _noMinification(sources, // @arg StringArray - JavaScript SourceCode file path. [path, ...] 546 | options, // @arg Object - { keep, nowrap, ... } see Minify() 547 | fn) { // @arg Function = null - callback function. fn(err:Error, result:String) 548 | 549 | var js = (options.header || "") + _concatFiles(sources) + (options.footer || ""); 550 | 551 | if (options.label && options.label.length) { 552 | js = Minify_preprocess( js, options.label ); 553 | } 554 | if (fn) { 555 | fn(null, js); 556 | } 557 | } 558 | 559 | function _trimCodeBlock(js, // @arg String - JavaScript expression string. 560 | labels) { // @arg StringArray - [label, ...] 561 | // @ret String 562 | return labels.reduce(function(js, label) { 563 | // trim: 564 | // 565 | // {@label ... }@label 566 | // 567 | var line = RegExp("\\{@" + label + "\\b(?:[^\\n]*)\\}@" + 568 | label + "\\b", "g"); 569 | 570 | // trim: 571 | // 572 | // {@label 573 | // ... 574 | // }@label 575 | // 576 | var lines = RegExp("\\{@" + label + "\\b(?:[^\\n]*)\n(?:[\\S\\s]*?)?\\}@" + 577 | label + "\\b", "g"); 578 | 579 | 580 | return js.replace(line, " ").replace(lines, " "); 581 | }, js); 582 | } 583 | 584 | function _concatFiles(sources) { // @arg FilePathArray 585 | // @ret String 586 | return sources.map(function(path) { 587 | if (fs.existsSync(path)) { 588 | return fs.readFileSync(path, "utf8"); 589 | } 590 | console.log(path + " is not exists"); 591 | return ""; 592 | }).join(""); 593 | } 594 | 595 | // --- validate / assertions ------------------------------- 596 | //{@dev 597 | function _keys(value, keys) { 598 | var items = keys.split(","); 599 | 600 | return Object.keys(value).every(function(key) { 601 | return items.indexOf(key) >= 0; 602 | }); 603 | } 604 | 605 | function _if(value, fn, hint) { 606 | if (value) { 607 | throw new Error(fn.name + " " + hint); 608 | } 609 | } 610 | //}@def 611 | 612 | })(GLOBAL); 613 | 614 | -------------------------------------------------------------------------------- /run/page.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // page --verbose 4 | (function(global) { 5 | 6 | var USAGE = _multiline(function() {/* 7 | Usage: 8 | node bin/page.js [-h][--help] 9 | [-v][--verify] 10 | [--noverify] 11 | [--noverbose] 12 | [--nopublish] 13 | [--release] 14 | */}); 15 | 16 | var ERR = "\u001b[31m"; 17 | var WARN = "\u001b[33m"; 18 | var INFO = "\u001b[32m"; 19 | var CLR = "\u001b[0m"; 20 | 21 | var fs = require("fs"); 22 | var wmlib = process.argv[1].split("/").slice(0, -2).join("/") + "/lib/"; // "WebModule/lib/" 23 | var wmmodsys = require(wmlib + "ModuleSystem.js"); 24 | var argv = process.argv.slice(2); 25 | var modpkg = JSON.parse(fs.readFileSync("package.json", "utf8")); 26 | 27 | var options = _parseCommandLineOptions(argv, { 28 | help: false, // show help. --help or -h 29 | verify_state: true, // WebModule.verify state. --noverify 30 | verbose_state: true, // WebModule.verbose state. --noverbose 31 | publish_state: true, // WebModule.publish state. --nopublish 32 | verbose: false, // verbos mode. --verbose or -v 33 | }); 34 | 35 | _createTestPages(); 36 | 37 | /* 38 | ▾ lib/ 39 | WebModule.js 40 | ▾ test/ 41 | testcase.js 42 | wmtools.js 43 | ▾ browser/ 44 | ▾ template/ 45 | index.html 46 | worker.js 47 | index.html 48 | worker.js 49 | ▾ node/ 50 | ▾ template/ 51 | index.js 52 | index.js 53 | ▾ nw/ 54 | ▾ template/ 55 | index.html 56 | index.html 57 | package.json 58 | ▾ el/ 59 | ▾ template/ 60 | index.html 61 | index.html 62 | main.js 63 | package.json 64 | */ 65 | 66 | function _createTestPages() { 67 | var releaseBuild = false; 68 | var deps = wmmodsys.getDependencies(releaseBuild); 69 | 70 | if (options.verbose) { 71 | // console.log("\u001b[31m" + "packages: " + JSON.stringify(deps.packages, null, 2) + "\u001b[0m"); 72 | console.log("\u001b[32m" + "tree: " + JSON.stringify(deps.tree, null, 2) + "\u001b[0m"); 73 | console.log("\u001b[33m" + "modules: " + JSON.stringify(deps.modules, null, 2) + "\u001b[0m"); 74 | console.log("files: " + JSON.stringify(deps.files, null, 2)); 75 | } 76 | if ( !fs["existsSync"]("test") ) { 77 | console.error(ERR + "ERROR. test/ directory was not found." + CLR); 78 | } 79 | var browser = _convertBrowserFile(deps.files, modpkg); 80 | var worker = _convertWorkerFile(deps.files, modpkg); 81 | var node = _convertNodeFile(deps.files, modpkg); 82 | var nw = _convertNWFile(deps.files, modpkg); 83 | var el = _convertElectronFile(deps.files, modpkg); 84 | 85 | if (options.verbose) { 86 | if (browser) { console.log( "update test/browser/index.html: \n " + browser.replace(/\n/g, "\n " ) ); } 87 | if (worker) { console.log( "update test/browser/worker.js: \n " + worker.replace(/\n/g, "\n " ) ); } 88 | if (node) { console.log( "update test/node/index.js: \n " + node.replace(/\n/g, "\n " ) ); } 89 | if (nw) { console.log( "update test/nw/index.html: \n " + nw.replace(/\n/g, "\n " ) ); } 90 | if (el) { console.log( "update test/el/index.html: \n " + el.replace(/\n/g, "\n " ) ); } 91 | } 92 | // package.json に webmodule{browser|worker|node|nw|el} プロパティが無い場合でも、 93 | // テスト用のページはそれぞれ生成します。 94 | if (browser) { fs.writeFileSync("test/browser/index.html", browser); } 95 | if (worker) { fs.writeFileSync("test/browser/worker.js", worker); } 96 | if (node) { fs.writeFileSync("test/node/index.js", node); } 97 | if (nw) { fs.writeFileSync("test/nw/index.html", nw); } 98 | if (el) { fs.writeFileSync("test/el/index.html", el); } 99 | 100 | /* 101 | // copy test/template/nw.package.json to test/package.json 102 | var nwpkg = fs.readFileSync("test/template/nw.package.json", "utf8"); 103 | 104 | fs.writeFileSync("test/package.json", nwpkg); 105 | */ 106 | } 107 | 108 | function _convertBrowserFile(files, // @arg Object - { node, worker, browser, nw, el, label } 109 | packagejson) { // @arg Object - module package.json 110 | // @ret String 111 | var target = wmmodsys.collectBuildTarget(packagejson); 112 | var wm = packagejson["webmodule"]; 113 | 114 | if (fs.existsSync("test/browser/template/index.html")) { 115 | var browser = { 116 | template: fs.readFileSync("test/browser/template/index.html", "utf8"), 117 | enable: wm.browser, 118 | __MODULES__: files.browser.map(_script_updir).join("\n"), 119 | __WMTOOLS__: _script("../wmtools.js"), 120 | __SOURCES__: target.browser.source.map(_script_updir).join("\n"), 121 | __OUTPUT__: _script_updir(target.browser.output), 122 | __TEST_CASE__: _script("../testcase.js"), 123 | }; 124 | return _mapping(browser, _ignoreNotationVariability(_migration(browser.template))); 125 | } 126 | return ""; 127 | } 128 | 129 | function _convertWorkerFile(files, // @arg Object - { node, worker, browser, nw, el, label } 130 | packagejson) { // @arg Object - module package.json 131 | // @ret String 132 | var target = wmmodsys.collectBuildTarget(packagejson); 133 | var wm = packagejson["webmodule"]; 134 | 135 | if (fs.existsSync("test/browser/template/worker.js")) { 136 | var worker = { 137 | template: fs.readFileSync("test/browser/template/worker.js", "utf8"), 138 | enable: wm.worker, 139 | __MODULES__: files.worker.map(_import_updir).join("\n "), 140 | __WMTOOLS__: _import("../wmtools.js"), 141 | __SOURCES__: target.worker.source.map(_import_updir).join("\n "), 142 | __OUTPUT__: _import_updir(target.worker.output), 143 | __TEST_CASE__: _import("../testcase.js"), 144 | }; 145 | return _mapping(worker, _ignoreNotationVariability(_migration(worker.template))); 146 | } 147 | return ""; 148 | } 149 | 150 | function _convertNodeFile(files, // @arg Object - { node, worker, browser, nw, el, label } 151 | packagejson) { // @arg Object - module package.json 152 | // @ret String 153 | var target = wmmodsys.collectBuildTarget(packagejson); 154 | var wm = packagejson["webmodule"]; 155 | 156 | if (fs.existsSync("test/node/template/index.js")) { 157 | var node = { 158 | template: fs.readFileSync("test/node/template/index.js", "utf8"), 159 | enable: wm.node, 160 | __MODULES__: files.node.map(_require_updir).join("\n"), 161 | __WMTOOLS__: _require("../wmtools.js"), // node.js require spec. add "./" 162 | __SOURCES__: target.node.source.map(_require_updir).join("\n"), 163 | __OUTPUT__: _require_updir(target.node.output), 164 | __TEST_CASE__: _require("../testcase.js"), // node.js require spec. add "./" 165 | }; 166 | return _mapping(node, _ignoreNotationVariability(_migration(node.template))); 167 | } 168 | return ""; 169 | } 170 | 171 | function _convertNWFile(files, // @arg Object - { node, worker, browser, nw, el, label } 172 | packagejson) { // @arg Object - module package.json 173 | // @ret String 174 | var target = wmmodsys.collectBuildTarget(packagejson); 175 | var wm = packagejson["webmodule"]; 176 | 177 | if (fs.existsSync("test/nw/template/index.html")) { 178 | var nw = { 179 | template: fs.readFileSync("test/nw/template/index.html", "utf8"), 180 | enable: wm.nw, 181 | __MODULES__: files.nw.map(_script_updir).join("\n"), 182 | __WMTOOLS__: _script("../wmtools.js"), 183 | __SOURCES__: target.nw.source.map(_script_updir).join("\n"), 184 | __OUTPUT__: _script_updir(target.nw.output), 185 | __TEST_CASE__: _script("../testcase.js"), 186 | }; 187 | return _mapping(nw, _ignoreNotationVariability(_migration(nw.template))); 188 | } 189 | return ""; 190 | } 191 | 192 | function _convertElectronFile(files, // @arg Object - { node, worker, browser, nw, el, label } 193 | packagejson) { // @arg Object - module package.json 194 | // @ret String 195 | var target = wmmodsys.collectBuildTarget(packagejson); 196 | var wm = packagejson["webmodule"]; 197 | 198 | if (fs.existsSync("test/el/template/index.html")) { 199 | var el = { 200 | template: fs.readFileSync("test/el/template/index.html", "utf8"), 201 | enable: wm.el, 202 | __MODULES__: files.el.map(_script_updir).join("\n"), 203 | __WMTOOLS__: _script("../wmtools.js"), 204 | __SOURCES__: target.el.source.map(_script_updir).join("\n"), 205 | __OUTPUT__: _script_updir(target.el.output), 206 | __TEST_CASE__: _script("../testcase.js"), 207 | }; 208 | return _mapping(el, _ignoreNotationVariability(_migration(el.template))); 209 | } 210 | return ""; 211 | } 212 | 213 | function _script(file) { return ''; } 214 | function _script_updir(file) { return ''; } 215 | function _import(file) { return 'importScripts("' + file + '");'; } 216 | function _import_updir(file) { return 'importScripts("../../' + file + '");'; } 217 | function _require(file) { return 'require("' + file + '");'; } 218 | function _require_updir(file) { return 'require("../../' + file + '");'; } 219 | 220 | function _mapping(res, template) { 221 | var enable = res.enable; 222 | return template.replace("__MODULES__", enable ? res.__MODULES__ : ""). 223 | replace("__WMTOOLS__", enable ? res.__WMTOOLS__ : ""). 224 | replace("__SOURCES__", enable ? res.__SOURCES__ : ""). 225 | replace("__OUTPUT__", enable ? res.__OUTPUT__ : ""). 226 | replace("__TEST_CASE__", enable ? res.__TEST_CASE__ : ""). 227 | replace("__WEBMODULE_VERIFY__", options.verify_state ? "true" : "false"). 228 | replace("__WEBMODULE_VERBOSE__", options.verbose_state ? "true" : "false"). 229 | replace("__WEBMODULE_PUBLISH__", options.publish_state ? "true" : "false"); 230 | } 231 | 232 | function _ignoreNotationVariability(template) { // ( fix typo :) 233 | return template.replace("__MODULE__", "__MODULES__"). 234 | replace("__WMTOOL__", "__WMTOOLS__"). 235 | replace("__SOURCE__", "__SOURCES__"). 236 | replace("__OUTPUTS__", "__OUTPUT__"). 237 | replace("__TESTCASE__", "__TEST_CASE__"); 238 | } 239 | 240 | function _migration(template) { 241 | return template.replace("__SCRIPT__", "__MODULES__\n__WMTOOLS__\n__SOURCES__\n__OUTPUT__\n__TEST_CASE__"); 242 | } 243 | 244 | function _parseCommandLineOptions(argv, options) { 245 | for (var i = 0, iz = argv.length; i < iz; ++i) { 246 | switch (argv[i]) { 247 | case "-h": 248 | case "--help": options.help = true; break; 249 | case "-v": 250 | case "--verbose": options.verbose = true; break; 251 | case "--noverify": options.verify_state = false; break; 252 | case "--noverbose": options.verbose_state = false; break; 253 | case "--nopublish": options.publish_state = false; break; 254 | case "--release": options.verify_state = false; 255 | options.verbose_state = false; 256 | options.publish_state = false; break; 257 | default: 258 | throw new TypeError("UNKNOWN argument: " + argv[i]); 259 | } 260 | } 261 | return options; 262 | } 263 | 264 | function _multiline(fn) { // @arg Function: 265 | // @ret String: 266 | return (fn + "").split("\n").slice(1, -1).join("\n"); 267 | } 268 | 269 | })(GLOBAL); 270 | 271 | -------------------------------------------------------------------------------- /run/patch.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | (function(global) { 4 | 5 | var fs = require("fs"); 6 | 7 | patch(process.cwd() + "/" + "package.json"); 8 | 9 | function patch(file) { 10 | var packagejson1 = fs.readFileSync(file, "UTF-8"); 11 | var packagejson2 = packagejson1.replace(/"version":(\s+)"(\d+)\.(\d+)\.(\d+)"/, function(_, space, major, minor, patch) { 12 | return '"version":' + space + '"' + major + "." + minor + "." + (parseInt(patch, 10) + 1) + '"'; 13 | }); 14 | 15 | var json1 = JSON.parse(packagejson1); 16 | var json2 = JSON.parse(packagejson2); 17 | var version1 = parseInt(json1.version.split(".")[2] || 0, 10); 18 | var version2 = parseInt(json2.version.split(".")[2] || 0, 10); 19 | 20 | if (version1 + 1 === version2) { 21 | console.log("update patch version. " + json1.version + " -> " + json2.version); 22 | fs.writeFileSync(file, packagejson2); 23 | //console.log( fs.readFileSync(file, "UTF-8") ); 24 | } else { 25 | console.error("format error."); 26 | } 27 | } 28 | 29 | })(GLOBAL); 30 | 31 | -------------------------------------------------------------------------------- /run/score.js: -------------------------------------------------------------------------------- 1 | (function(global) { 2 | 3 | var _USAGE = _multiline(function() {/* 4 | Usage: 5 | node WebModule/run/score.js [--help] 6 | [--verbose] 7 | [--title page-title] 8 | [--output output-dir] 9 | input-file [input-file ...] 10 | 11 | See: 12 | https://github.com/uupaa/Plato.js/wiki/Plato 13 | */}); 14 | 15 | var ERR = "\u001b[31m"; 16 | var WARN = "\u001b[33m"; 17 | var INFO = "\u001b[32m"; 18 | var CLR = "\u001b[0m"; 19 | 20 | // require("../lib/plato.js") は、score.js を呼び出したスクリプトのディレクトリを基準としたパスになるため、WebModule/run/lib/xxx.js などを require できない 21 | // fs.read("../lib/plato.js") は、score.js を呼び出したスクリプトのディレクトリを記述したパスになる 22 | 23 | //var Plato = require("../lib/plato"); // WebModule/run/lib/plato.js 24 | var fs = require("fs"); 25 | var cp = require("child_process"); 26 | var argv = process.argv.slice(2); 27 | var pkg = JSON.parse(fs.readFileSync("./package.json", "utf8")); 28 | var wmlib = process.argv[1].split("/").slice(0, -2).join("/") + "/lib/"; // "WebModule/lib/" 29 | var mod = require(wmlib + "ModuleSystem.js"); 30 | var target = mod.collectBuildTarget(pkg); 31 | 32 | var options = _parseCommandLineOptions({ 33 | help: false, // Boolean: true is show help. 34 | verbose: false, // Boolean: true is verbose mode. 35 | title: pkg.name, // String: title. 36 | output: "./lint/plato", // String: output dir. 37 | files: target.sources // StringArray: input files. [file, ...] 38 | }); 39 | 40 | if (options.help) { 41 | console.log(WARN + _USAGE + CLR); 42 | return; 43 | } 44 | if (!options.files.length) { 45 | console.log(ERR + "Input files are empty." + CLR); 46 | return; 47 | } 48 | 49 | Plato({ 50 | "verbose": options.verbose, 51 | "title": options.title, 52 | "output": options.output, 53 | "files": options.files 54 | }, function() { }); 55 | 56 | 57 | // --- class / interfaces ---------------------------------- 58 | function Plato(options, // @arg Object - { verbose, title, output, files } 59 | callback) { // @arg Function = null - callback(err):void 60 | //{@dev 61 | _if(options.constructor !== ({}).constructor, Plato, "options"); 62 | _if(!_keys(options, "verbose,title,output,files"), Plato, "options"); 63 | if (callback) { 64 | _if(typeof callback !== "function", Plato, "callback"); 65 | } 66 | //}@dev 67 | 68 | _do(options, callback || null); 69 | } 70 | 71 | // --- implements ------------------------------------------ 72 | function _do(options, callback) { 73 | 74 | var command = "plato"; 75 | 76 | if (options.title) { 77 | command += " --title " + options.title; 78 | } 79 | command += " --dir " + options.output; 80 | command += " --eslint .eslintrc"; 81 | command += " --exclude WebModule.js"; 82 | command += " " + options.files.join(" "); 83 | 84 | if (options.verbose) { 85 | console.log("command: " + command); 86 | } 87 | cp.exec(command, function(err) { 88 | if (err) { 89 | console.error(ERR + err.message + CLR); 90 | } else { 91 | if (options.verbose) { 92 | console.log(command); 93 | } 94 | _parseHistoryJS(); 95 | _parseHistoryJSON(); 96 | _parseReportJS(); 97 | _parseReportJSON(); 98 | } 99 | if (callback) { 100 | callback(err); 101 | } 102 | }); 103 | } 104 | 105 | // --------------------------------------------------------- 106 | function _parseHistoryJS() { 107 | var fileName = "./lint/plato/report.history.js"; 108 | 109 | if (fs.existsSync(fileName)) { 110 | _write(fileName, "__history = ", _load(fileName), ""); 111 | } 112 | } 113 | function _parseHistoryJSON() { 114 | var fileName = "./lint/plato/report.history.json"; 115 | 116 | if (fs.existsSync(fileName)) { 117 | _write(fileName, "", _load(fileName), ""); 118 | } 119 | } 120 | 121 | function _parseReportJS() { 122 | var fileName = "./lint/plato/report.js"; 123 | 124 | if (fs.existsSync(fileName)) { 125 | _write(fileName, "__report = ", _sort(_load(fileName)), ""); 126 | } 127 | } 128 | function _parseReportJSON() { 129 | var fileName = "./lint/plato/report.json"; 130 | 131 | if (fs.existsSync(fileName)) { 132 | _write(fileName, "", _sort(_load(fileName)), ""); 133 | } 134 | } 135 | 136 | function _load(fileName) { 137 | if (/\.json$/.test(fileName)) { 138 | return JSON.parse( fs.readFileSync(fileName, "utf8") ); 139 | } else if (/\.js$/.test(fileName)) { 140 | return eval("(" + fs.readFileSync(fileName, "utf8") + ")"); 141 | } 142 | return fs.readFileSync(fileName, "utf8"); 143 | } 144 | 145 | function _sort(json) { 146 | var result = {}; 147 | var keys = Object.keys(json).sort(); 148 | 149 | for (var i = 0, iz = keys.length; i < iz; ++i) { 150 | result[keys[i]] = json[keys[i]]; 151 | } 152 | return result; 153 | } 154 | 155 | function _write(fileName, prefix, json, postfix) { 156 | fs.writeFileSync(fileName, prefix + JSON.stringify(json, null, 2) + postfix + "\n"); 157 | } 158 | 159 | //{@dev 160 | function _keys(value, keys) { 161 | var items = keys.split(","); 162 | 163 | return Object.keys(value).every(function(key) { 164 | return items.indexOf(key) >= 0; 165 | }); 166 | } 167 | 168 | function _if(value, fn, hint) { 169 | if (value) { 170 | throw new Error(fn.name + " " + hint); 171 | } 172 | } 173 | //}@dev 174 | 175 | 176 | function _parseCommandLineOptions(options) { 177 | for (var i = 0, iz = argv.length; i < iz; ++i) { 178 | switch (argv[i]) { 179 | case "-h": 180 | case "--help": options.help = true; break; 181 | case "-v": 182 | case "--verbose": options.verbose = true; break; 183 | case "--title": options.title = argv[++i]; break; 184 | case "--output": options.output = argv[++i]; break; 185 | default: 186 | var file = argv[i]; 187 | if (options.files.indexOf(file) < 0) { // avoid duplicate 188 | options.files.push(file); 189 | } 190 | } 191 | } 192 | return options; 193 | } 194 | 195 | function _multiline(fn) { // @arg Function: 196 | // @ret String: 197 | return (fn + "").split("\n").slice(1, -1).join("\n"); 198 | } 199 | 200 | })(GLOBAL); 201 | 202 | -------------------------------------------------------------------------------- /run/setup.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | (function(global) { 4 | 5 | var _USAGE = _multiline(function() {/* 6 | Usage: 7 | WebModule/run/setup.js [-h or --help] 8 | [-v or --verbose] 9 | [--alt] 10 | [--bin] 11 | */}); 12 | 13 | var ERR = "\u001b[31m"; 14 | var WARN = "\u001b[33m"; 15 | var INFO = "\u001b[32m"; 16 | var CLR = "\u001b[0m"; 17 | 18 | 19 | var fs = require("fs"); 20 | var cp = require("child_process"); 21 | var wmlib = process.argv[1].split("/").slice(0, -2).join("/") + "/lib/"; // "WebModule/lib/" 22 | var Task = require(wmlib + "Task.js"); 23 | var readline = require("readline"); 24 | var argv = process.argv.slice(2); 25 | 26 | var repositoryFullName = process.cwd().split("/").pop(); 27 | var repositoryName = repositoryFullName.indexOf(".") >= 0 28 | ? repositoryFullName.split(".").slice(0, -1).join(".") 29 | : repositoryFullName; 30 | 31 | var BASE_MODEL_DIR = "BASE_MODEL/"; 32 | var copySourceDir = process.argv[1].split("/").slice(0, -2).join("/") + "/"; 33 | var copyTargetDir = process.cwd() + "/"; 34 | var fileTree = JSON.parse(fs.readFileSync(copySourceDir + BASE_MODEL_DIR + ".files.json", "UTF-8")); 35 | 36 | var GITHUB_TEMPLATE_DIR = ".github/"; 37 | var GITHUB_TEMPLATE_FILElIST = [ 38 | "CONTRIBUTING.md", 39 | "CONTRIBUTORS.md", 40 | "ISSUE_TEMPLATE.md", 41 | "PULL_REQUEST_TEMPLATE.md" 42 | ]; 43 | 44 | console.log(INFO + " - repositoryFullName: " + repositoryFullName + CLR); // "Foo.js" 45 | console.log(INFO + " - repositoryName: " + repositoryName + CLR); // "Foo" 46 | console.log(INFO + " - copy source dir: " + copySourceDir + CLR); // "/Users/uupaa/oss/WebModule/" 47 | console.log(INFO + " - copy target dir: " + copyTargetDir + CLR + "\n"); // "/Users/uupaa/oss/Foo.js/" 48 | 49 | //console.log(JSON.stringify(fileTree, null, 2)); 50 | 51 | // ------------------------------------------------------------- 52 | var options = _parseCommandLineOptions({ 53 | help: false, // Boolean - show help. 54 | verbose: false, // Boolean - verbose mode. 55 | alt: false, // Boolean - create alt directory. 56 | bin: false, // Boolean - create bin directory. 57 | desc: "Module description.", // String - Module description. 58 | }); 59 | 60 | if (options.help) { 61 | console.log(WARN + _USAGE + CLR); 62 | return; 63 | } 64 | 65 | if (!options.alt) { 66 | delete fileTree.alt; 67 | } 68 | if (!options.bin) { 69 | delete fileTree.bin; 70 | } 71 | 72 | if (fs.existsSync("README.md") ) { 73 | options.desc = fs.readFileSync("README.md", "UTF-8").split("\n").slice(-2).join("").trim(); 74 | } 75 | 76 | getGitHubUserName(function(userName) { 77 | 78 | options.userName = userName; 79 | _clone(copySourceDir + BASE_MODEL_DIR, 80 | copyTargetDir, fileTree, 81 | function() { 82 | _copyGitHubTemplateFiles(copySourceDir + GITHUB_TEMPLATE_DIR, 83 | copyTargetDir + GITHUB_TEMPLATE_DIR, 84 | GITHUB_TEMPLATE_FILElIST, 85 | function() { 86 | console.log(" "); 87 | console.log(INFO + " done." + CLR + "\n"); 88 | console.log(INFO + " You can be next actions." + CLR); 89 | console.log(INFO + " `$ npm run` # Dump all WebModule commands" + CLR); 90 | console.log(INFO + " `$ npm start` # Start local http server" + CLR); 91 | console.log(INFO + " `$ npm run sync` # Update npm modules" + CLR); 92 | console.log(INFO + " `$ npm t` # Minify and Test" + CLR); 93 | }); 94 | }); 95 | 96 | }, function(err) { 97 | console.error(ERR + "Error: git config --get user.name" + CLR); 98 | }); 99 | 100 | // ========================================================= 101 | function getGitHubUserName(callback, errorCallback) { 102 | cp.exec("git config --get remote.origin.url", function(err, stdout, stderr) { 103 | if (err) { 104 | errorCallback(err); 105 | } else { 106 | var value = stdout.trim(); 107 | var result = ""; 108 | 109 | // HTTPS format // "https://github.com/uupaa/WMExample.js.git" 110 | // SSH format // "git@github.com:uupaa/WMExample.js.git" 111 | 112 | if (/^https/.test(value)) { 113 | result = value.split("github.com/" )[1].split("/")[0]; 114 | } else if (/^git@github.com/.test(value)) { 115 | result = value.split("git@github.com:")[1].split("/")[0]; 116 | } 117 | callback(result); 118 | } 119 | }); 120 | } 121 | 122 | function _clone(copySourceDir, // @arg String - copy from dir. has tail slash(/) 123 | copyTargetDir, // @arg String - copy to dir. has tail slash(/) 124 | fileTree, // @arg Object - source file tree. 125 | callback) { // @arg Function - finished callback. 126 | 127 | var overwriteFiles = []; // [ [targetFile, sourceText], ... ] 128 | 129 | _doClone(overwriteFiles, copySourceDir, copyTargetDir, fileTree); 130 | 131 | if (overwriteFiles.length) { 132 | var rl = readline.createInterface(process.stdin, process.stdout); 133 | Task.loop(overwriteFiles, _tick, function() { 134 | rl.close(); 135 | callback(); 136 | }); 137 | 138 | function _tick(task, index, overwriteFiles) { 139 | var ary = overwriteFiles[index]; 140 | var targetFile = ary[0]; 141 | var sourceText = ary[1]; 142 | 143 | rl.question(" exists: " + targetFile + " - overwrite it? (y/n): ", function(answer) { 144 | 145 | if (/^y$/i.test(answer)) { 146 | console.log(WARN + " overwrite: " + targetFile + CLR); 147 | fs.writeFileSync(targetFile, sourceText); 148 | } else { 149 | console.log(" skip: " + targetFile); 150 | } 151 | task.pass(); 152 | }); 153 | } 154 | } else { 155 | callback(); 156 | } 157 | } 158 | 159 | function _doClone(overwriteFiles, copySourceDir, copyTargetDir, fileTree) { 160 | 161 | for (fileName in fileTree) { 162 | _loop(overwriteFiles, fileName, fileTree); 163 | } 164 | 165 | function _loop(overwriteFiles, // @arg FileStringArray - ["file", ...] 166 | name, // @arg FileNameString|DirNameString - "README.md", "lib", ... 167 | fileTree) { // @arg Object - _CLONE_FILES or _CLONE_FILES subtree. 168 | var options = fileTree[name]; // [ scan ] 169 | var scan = Array.isArray(options) && options.indexOf("scan") >= 0; 170 | var disable = Array.isArray(options) && options.indexOf("disable") >= 0; 171 | var isDirEntry = !Array.isArray(options); // dir is {}, file is [] 172 | 173 | if (disable) { 174 | console.log(" disable: " + _repleaceText(copyTargetDir + name)); 175 | return; 176 | } 177 | if (isDirEntry) { 178 | if ( !fs.existsSync(copyTargetDir + name) ) { 179 | console.log(" mkdir: " + copyTargetDir + name + "/"); 180 | fs.mkdirSync(copyTargetDir + name); 181 | } 182 | // recursive call 183 | _doClone(overwriteFiles, 184 | copySourceDir + name + "/", 185 | copyTargetDir + name + "/", 186 | fileTree[name]); 187 | 188 | } else { 189 | var sourceFile = copySourceDir + name; 190 | var targetFile = _repleaceText(copyTargetDir + name); // replace file name. "lib/REPOSITORY_NAME.js" -> "lib/Foo.js" 191 | var fileExists = fs.existsSync(targetFile); 192 | var sourceText = fs.readFileSync(sourceFile, "UTF-8"); 193 | var targetText = fileExists ? fs.readFileSync(targetFile, "UTF-8") : ""; 194 | 195 | if (scan) { 196 | sourceText = _repleaceText(sourceText); 197 | } 198 | if (targetText && targetText !== sourceText) { 199 | overwriteFiles.push([targetFile, sourceText]); 200 | } else { 201 | if (fileExists) { 202 | console.log(" exists: " + targetFile); 203 | } else { 204 | console.log(" clone: " + targetFile); 205 | fs.writeFileSync(targetFile, sourceText); 206 | } 207 | } 208 | } 209 | } 210 | 211 | function _repleaceText(text) { 212 | text = text.replace(/<>/g, options.desc); // "description" 213 | text = text.replace(/<>/g, options.userName); // "uupaa" 214 | text = text.replace(/<>/g, repositoryFullName.toLowerCase()); // "foo.js" 215 | text = text.replace(/<>/g, repositoryName.toLowerCase()); // "foo" 216 | text = text.replace(/<>/g, repositoryFullName); // "Foo.js" 217 | text = text.replace(/REPOSITORY_FULLNAME/g, repositoryFullName); // "Foo.js" 218 | text = text.replace(/<>/g, repositoryName); // "Foo" 219 | text = text.replace(/__REPOSITORY_NAME__/g, _spacer(repositoryName.length)); // "Foo" 220 | text = text.replace(/REPOSITORY_NAME/g, repositoryName); // "Foo" 221 | text = text.replace(/__19_SPACE_________/g, _spacer(repositoryName.length)); // "Foo" 222 | return text; 223 | } 224 | } 225 | 226 | function _copyGitHubTemplateFiles(copySourceDir, // @arg String - copy from dir. has tail slash(/) 227 | copyTargetDir, // @arg String - copy to dir. has tail slash(/) 228 | fileList, // @arg StringArray - 229 | callback) { // @arg Function - finished callback. 230 | var overwriteFiles = []; // [ [targetFile, sourceText], ... ] 231 | 232 | if ( !fs.existsSync(copyTargetDir) ) { 233 | console.log(" mkdir: " + copyTargetDir); 234 | fs.mkdirSync(copyTargetDir); 235 | } 236 | fileList.forEach(function(name) { 237 | var sourceFile = copySourceDir + name; 238 | var targetFile = copyTargetDir + name; 239 | var fileExists = fs.existsSync(targetFile); 240 | var sourceText = fs.readFileSync(sourceFile, "UTF-8"); 241 | var targetText = fileExists ? fs.readFileSync(targetFile, "UTF-8") : ""; 242 | 243 | if (targetText && targetText !== sourceText) { 244 | overwriteFiles.push([targetFile, sourceText]); 245 | } else { 246 | if (fileExists) { 247 | console.log(" exists: " + targetFile); 248 | } else { 249 | console.log(" clone: " + targetFile); 250 | fs.writeFileSync(targetFile, sourceText); 251 | } 252 | } 253 | }); 254 | 255 | if (overwriteFiles.length) { 256 | var rl = readline.createInterface(process.stdin, process.stdout); 257 | Task.loop(overwriteFiles, _tick, function() { 258 | rl.close(); 259 | callback(); 260 | }); 261 | 262 | function _tick(task, index, overwriteFiles) { 263 | var ary = overwriteFiles[index]; 264 | var targetFile = ary[0]; 265 | var sourceText = ary[1]; 266 | 267 | rl.question(" exists: " + targetFile + " - overwrite it? (y/n): ", function(answer) { 268 | 269 | if (/^y$/i.test(answer)) { 270 | console.log(WARN + " overwrite: " + targetFile + CLR); 271 | fs.writeFileSync(targetFile, sourceText); 272 | } else { 273 | console.log(" skip: " + targetFile); 274 | } 275 | task.pass(); 276 | }); 277 | } 278 | } else { 279 | callback(); 280 | } 281 | } 282 | 283 | function _parseCommandLineOptions(options) { // @arg Object: 284 | // @ret Object: 285 | for (var i = 0, iz = argv.length; i < iz; ++i) { 286 | switch (argv[i]) { 287 | case "-h": 288 | case "--help": options.help = true; break; 289 | case "-v": 290 | case "--verbose": options.verbose = true; break; 291 | case "--alt": options.alt = true; break; 292 | case "--bin": options.bin = true; break; 293 | } 294 | } 295 | return options; 296 | } 297 | 298 | function _spacer(n) { // @arg Integer 299 | // @ret String 300 | return " ".slice(0, n); 301 | } 302 | 303 | function _multiline(fn) { // @arg Function: 304 | // @ret String: 305 | return (fn + "").split("\n").slice(1, -1).join("\n"); 306 | } 307 | 308 | })(GLOBAL); 309 | 310 | -------------------------------------------------------------------------------- /run/sim.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | (function(global) { 4 | 5 | var SIM_OPEN = "xcrun simctl openurl __UUID__ __URL__"; 6 | var SIM_ENUM_DEVICE = "xcrun simctl list | grep -v com"; 7 | var SIM_START = "xcrun instruments -w __UUID__"; 8 | //var SIM_SHUTDOWN = "xcrun simctl shutdown "; 9 | var KILL_SIM_PROCESS = "kill `ps -e | grep 'iOS Simulator' | grep -v 'grep' | awk '{print $1}'`"; 10 | // --- console colors --- 11 | var ERR = "\u001b[31m"; // RED 12 | var WARN = "\u001b[33m"; // YELLOW 13 | var INFO = "\u001b[32m"; // GREEN 14 | var CLR = "\u001b[0m"; // WHITE 15 | var LB = "\n"; // line break 16 | 17 | var cp = require("child_process"); 18 | var argv = process.argv.slice(2); 19 | var options = { verbose: true }; 20 | 21 | if (argv[0] === "stop") { 22 | cp.exec(KILL_SIM_PROCESS); 23 | } else { 24 | start(open); 25 | } 26 | 27 | function start(next) { 28 | _enumDevieceList(function(deviceList, bootedDeviceUUID) { 29 | if (bootedDeviceUUID) { 30 | next(); 31 | } else { 32 | var uuid = deviceList["iPhone 5s"].uuid; 33 | 34 | cp.exec(SIM_START.replace("__UUID__", uuid), function(err, stdout, stderr) { 35 | if (options.verbose) { 36 | console.log(INFO + stdout + CLR); 37 | } 38 | setTimeout(function() { 39 | next(); 40 | }, 3000); // lazy 41 | }); 42 | } 43 | }); 44 | } 45 | 46 | function open() { 47 | _enumDevieceList(function(deviceList, bootedDeviceUUID) { 48 | if (bootedDeviceUUID) { 49 | var url = argv[0]; 50 | 51 | cp.exec(SIM_OPEN.replace("__UUID__", bootedDeviceUUID). 52 | replace("__URL__", url), function(err, stdout, stderr) { 53 | if (options.verbose) { 54 | console.log(INFO + stdout + CLR); 55 | //console.log(ERR + stderr + CLR); 56 | } 57 | }); 58 | } else { 59 | if (options.verbose) { 60 | console.log(WARN + "Page open fail. because iOS Simulator shutdown." + CLR); 61 | console.log(WARN + "Please try again after waiting for a while." + CLR); 62 | } 63 | } 64 | }); 65 | } 66 | 67 | // enum iOS Simulator devices 68 | function _enumDevieceList(callback) { 69 | cp.exec(SIM_ENUM_DEVICE, function(err, stdout, stderr) { 70 | 71 | // iPhone 5 (E6AA0287-6C06-4F03-A61E-C96B75B587CD) (Booted) 72 | // ~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ 73 | // name uuid state 74 | 75 | var lines = (stdout || "").trim(); 76 | var deviceList = {}; 77 | var bootedDeviceUUID = ""; 78 | 79 | lines.split("\n").forEach(function(line) { 80 | if (/(iPhone|iPad|iPod)/.test(line)) { 81 | if (/unavailable/.test(line)) { return; } 82 | 83 | var name = line.split("(")[0].trim(); 84 | var uuid = line.split("(")[1].split(")")[0].trim(); 85 | var state = line.split("(")[2].split(")")[0].trim(); 86 | 87 | deviceList[name] = { uuid: uuid, state: state }; 88 | 89 | if (state === "Booted") { 90 | bootedDeviceUUID = uuid; 91 | } 92 | } 93 | }); 94 | callback(deviceList, bootedDeviceUUID); 95 | }); 96 | } 97 | 98 | })(GLOBAL); 99 | 100 | -------------------------------------------------------------------------------- /run/sync.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | (function(global) { 4 | 5 | // --- console colors --- 6 | var ERR = "\u001b[31m"; // RED 7 | var WARN = "\u001b[33m"; // YELLOW 8 | var INFO = "\u001b[32m"; // GREEN 9 | var CLR = "\u001b[0m"; // WHITE 10 | var LB = "\n"; // line break 11 | 12 | var fs = require("fs"); 13 | var cp = require("child_process"); 14 | var readline = require("readline"); 15 | var wmlib = process.argv[1].split("/").slice(0, -2).join("/") + "/lib/"; // "WebModule/lib/" 16 | var mod = require(wmlib + "ModuleSystem.js"); 17 | var Task = require(wmlib + "Task.js"); 18 | var argv = process.argv.slice(2); 19 | 20 | var repositoryFullName = process.cwd().split("/").pop(); 21 | var repositoryName = repositoryFullName.indexOf(".") >= 0 22 | ? repositoryFullName.split(".").slice(0, -1).join(".") 23 | : repositoryFullName; 24 | 25 | var BASE_MODEL_DIR = "BASE_MODEL/"; 26 | var sourceDir = process.argv[1].split("/").slice(0, -2).join("/") + "/"; 27 | var targetDir = process.cwd() + "/"; 28 | var sourcePacakgeJSON = sourceDir + BASE_MODEL_DIR + "package.json"; 29 | var targetPackageJSON = targetDir + "package.json"; 30 | var wmJSON = JSON.parse(fs.readFileSync(sourceDir + "package.json", "UTF-8")); 31 | 32 | console.log( INFO + " - repositoryFullName: " + repositoryFullName + CLR ); // "Foo.js" 33 | console.log( INFO + " - repositoryName: " + repositoryName + CLR ); // "Foo" 34 | console.log( INFO + " - copy source dir: " + sourceDir + CLR ); // "/Users/uupaa/oss/WebModule/" 35 | console.log( INFO + " - copy target dir: " + targetDir + CLR ); // "/Users/uupaa/oss/Foo.js/" 36 | console.log( INFO + " - source package.json: " + sourcePacakgeJSON + CLR ); // "/Users/uupaa/oss/my/WebModule/BASE_MODEL/package.json" 37 | console.log( INFO + " - target package.json: " + targetPackageJSON + CLR + LB ); // "/Users/uupaa/oss/my/Foo.js/package.json" 38 | 39 | // --- sync tasks --- 40 | if (1) { 41 | syncPackageJSON(); 42 | upgradePackageJSON(); 43 | sortPackageJSONKeys(); 44 | prettyPrintPackageJSON(); 45 | buildWMTools("./test/wmtools.js"); 46 | migrateSourceCode(); 47 | } 48 | 49 | console.log(" module syncing and updates...\n"); 50 | 51 | function buildWMTools(output) { // @arg PathString 52 | var libs = ["Reflection.js", "Console.js", "Valid.js", "Help.js", "Task.js", "Test.js"]; 53 | var dir = "../WebModule/lib/"; 54 | var js = libs.map(function(lib) { 55 | return fs.readFileSync(dir + lib, "UTF-8") 56 | }).join("\n"); 57 | 58 | js = "// ['" + libs.join("', '") + "'].join()\n\n" + js; 59 | 60 | // overwrite if there is a difference in the old file. 61 | if (fs.existsSync(output)) { 62 | var oldjs = fs.readFileSync(output, "UTF-8"); 63 | 64 | if (oldjs !== js) { 65 | fs.writeFileSync(output, js); // overwrite 66 | } 67 | } else { 68 | fs.writeFileSync(output, js); 69 | } 70 | } 71 | 72 | function prettyPrintPackageJSON() { 73 | var json = JSON.parse(fs.readFileSync(targetPackageJSON, "UTF-8")); 74 | var txt = JSON.stringify(json, null, 2); 75 | 76 | txt = txt.replace(/"(keywords|label|contributors)": \[([^\]]*)\],/g, function(_, propertyName, items) { 77 | return '"' + propertyName + '": [' + items.trim().replace(/\s*\n+\s*/g, " ") + '],'; 78 | }); 79 | 80 | fs.writeFileSync(targetPackageJSON, txt); 81 | } 82 | 83 | // WebModule/BASE_MODEL/package.json sync to YOURWebModule/package.json 84 | function syncPackageJSON() { 85 | // srcJSON = WebMdule/BASE_MODEL/package.json 86 | // tgtJSON = YOURWebModule/package.json 87 | var srcJSON = JSON.parse(fs.readFileSync(sourcePacakgeJSON, "UTF-8").replace(/REPOSITORY_FULLNAME/g, repositoryFullName)); 88 | var tgtJSON = JSON.parse(fs.readFileSync(targetPackageJSON, "UTF-8")); 89 | var wmVersion = wmJSON.version; 90 | 91 | if (!tgtJSON.scripts) { 92 | tgtJSON.scripts = srcJSON.scripts; 93 | } else { 94 | // tgtJSON.script の順番を維持しつつ、コマンドを差し込めるように key と value の状態を保存する 95 | var tgtKeys = Object.keys(tgtJSON.scripts); 96 | var tgtValues = _Object_values(tgtJSON.scripts); 97 | 98 | for (var command in srcJSON.scripts) { // command = "sync", "min", "build", ... 99 | var src = srcJSON.scripts[command]; 100 | var tgt = tgtJSON.scripts[command] || ""; 101 | 102 | if (!tgt || tgt === src) { 103 | // tgt にコマンドAが無いか 104 | // tgt と src が同じならそのまま上書きする 105 | tgtJSON.scripts[command] = src; 106 | 107 | tgtKeys.push(command); 108 | tgtValues.push(src); 109 | } else if (tgt && tgt !== src) { 110 | // tgt の package.json にコマンドAが存在し src の package.json にもコマンドAがあるが、内容が異なる場合は、 111 | // tgt のコマンドAを優先し、src のコマンドA を 112 | // { "A_${wmversion}": srcJSON.scripts[command] } の形で挿入する。 113 | // tgt のコマンドAは上書きしない。 114 | var pos = tgtKeys.indexOf(command); 115 | 116 | tgtKeys.splice( pos, 0, command + "_" + wmVersion); 117 | tgtValues.splice( pos, 0, src); 118 | 119 | console.log(INFO + " - inject run-script: " + CLR + ' { "' + command + "_" + wmVersion + '": "' + src + '" }'); 120 | } 121 | } 122 | tgtJSON.scripts = _buildNewObjectByKeyOrder(tgtKeys, tgtValues); // rebuild 123 | } 124 | 125 | fs.writeFileSync(targetPackageJSON, JSON.stringify(tgtJSON, null, 2)); 126 | } 127 | 128 | function _Object_values(object) { 129 | var result = []; 130 | var keys = Object.keys(object); 131 | 132 | for (var i = 0, iz = keys.length; i < iz; ++i) { 133 | var key = keys[i]; 134 | result.push( object[key] ); 135 | } 136 | return result; 137 | } 138 | 139 | function _buildNewObjectByKeyOrder(keys, values) { 140 | var result = {}; 141 | 142 | for (var i = 0, iz = keys.length; i < iz; ++i) { 143 | result[keys[i]] = values[i]; 144 | } 145 | return result; 146 | } 147 | 148 | // package.json convert "x-build": { ... } to "webmodule": { ... } 149 | function upgradePackageJSON() { 150 | var json = JSON.parse(fs.readFileSync(targetPackageJSON, "UTF-8")); 151 | 152 | json = mod.upgradePackageJSON(json); 153 | 154 | fs.writeFileSync(targetPackageJSON, JSON.stringify(json, null, 2)); 155 | } 156 | 157 | function sortPackageJSONKeys() { 158 | var json = JSON.parse(fs.readFileSync(targetPackageJSON, "UTF-8")); 159 | var order = ["name", "version", "description", "url", "keywords", 160 | "repository", "scripts", "webmodule", 161 | "dependencies", "devDependencies", "lib", "main", 162 | "author", "license", "contributors"]; 163 | 164 | var keys = Object.keys(json).sort(function(a, b) { 165 | var pos1 = order.indexOf(a); 166 | var pos2 = order.indexOf(b); 167 | 168 | if (pos1 < 0) { pos1 = 999; } 169 | if (pos2 < 0) { pos2 = 999; } 170 | 171 | return pos1 - pos2; 172 | }); 173 | 174 | var result = {}; 175 | keys.forEach(function(key) { 176 | result[key] = json[key]; 177 | }); 178 | 179 | fs.writeFileSync(targetPackageJSON, JSON.stringify(result, null, 2)); 180 | } 181 | 182 | function migrateSourceCode() { 183 | var DEPRECATED_CODES = { 184 | "NODE": /_runOnNode\s*\=\s*"process" in global/, 185 | "WORKER": /_runOnWorker\s*\=\s*"WorkerLocation" in global/, 186 | "BROWSER": /_runOnBrowser\s*\=\s*"document" in global/, 187 | "EXPORTS": /if\s*\("process" in global\)\s*\{/ 188 | }; 189 | 190 | var json = JSON.parse(fs.readFileSync(targetPackageJSON, "UTF-8")); 191 | var sources = ["test/testcase.js"]; 192 | 193 | for (var key in json.webmodule) { // develop, label, browser, worker, node, nw, el, ... 194 | switch (key) { 195 | case "browser": 196 | case "worker": 197 | case "node": 198 | case "nw": 199 | case "el": 200 | sources = sources.concat(json.webmodule[key].source); 201 | break; 202 | } 203 | } 204 | sources = mod.toUniqueArray(sources); 205 | if (sources.length) { 206 | sources.forEach(function(file) { 207 | var js = fs.readFileSync(file, "UTF-8"); 208 | 209 | dumpDeprecatedCode(file, js, DEPRECATED_CODES.NODE); 210 | dumpDeprecatedCode(file, js, DEPRECATED_CODES.WORKER); 211 | dumpDeprecatedCode(file, js, DEPRECATED_CODES.BROWSER); 212 | dumpDeprecatedCode(file, js, DEPRECATED_CODES.EXPORTS); 213 | }); 214 | } 215 | 216 | function dumpDeprecatedCode(file, js, rex) { 217 | if (rex.test(js)) { 218 | js.split("\n").forEach(function(line, index) { 219 | if (rex.test(line)) { 220 | console.log(WARN + " Found deprecated code( " + file + ":" + index + " )" + 221 | "\t" + rex.source.replace(/\\s\*/g, " ").replace(/\\/g, "") + CLR); 222 | 223 | } 224 | }); 225 | } 226 | } 227 | } 228 | 229 | })(GLOBAL); 230 | 231 | -------------------------------------------------------------------------------- /run/watch.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | (function(global) { 4 | 5 | var USAGE = _multiline(function() {/* 6 | Usage: 7 | node bin/Watch.js [--help] 8 | [--verbose] 9 | [--run script][--action script] 10 | [--command script] 11 | [--delay n] 12 | watch-target-file [watch-target-file ...] 13 | 14 | See: 15 | https://github.com/uupaa/Watch.js/wiki/Watch 16 | */}); 17 | 18 | var ERR = "\u001b[31m"; // RED 19 | var WARN = "\u001b[33m"; // YELLOW 20 | var INFO = "\u001b[32m"; // GREEN 21 | var CLR = "\u001b[0m"; // WHITE 22 | 23 | var fs = require("fs"); 24 | var cp = require("child_process"); 25 | var argv = process.argv.slice(2); 26 | var pkg = JSON.parse(fs.readFileSync("./package.json", "utf8")); 27 | var wmlib = process.argv[1].split("/").slice(0, -2).join("/") + "/lib/"; // "WebModule/lib/" 28 | var mod = require(wmlib + "ModuleSystem.js"); 29 | var target = mod.collectBuildTarget(pkg); 30 | 31 | var options = _parseCommandLineOptions(argv, { 32 | help: false, // show help 33 | source: target.sources, // WatchTargetPathStringArray: [dir, file, ...] 34 | delay: 1000, // delay time (unit ms) 35 | runScript: "", // $ npm run {{script}} 36 | command: "", // $ command 37 | verbose: false, // verbose 38 | ignoreDir: [".watchignore"] // ignore dir name 39 | }); 40 | 41 | if (options.help) { 42 | console.log(WARN + USAGE + CLR); 43 | return; 44 | } 45 | if (!options.source.length) { 46 | console.log(ERR + "Input file is empty." + CLR); 47 | return; 48 | } 49 | 50 | Watch(options.source, { 51 | "delay": options.delay, 52 | "verbose": options.verbose, 53 | "ignoreDir": options.ignoreDir 54 | }, function(err, path) { // @arg Error: 55 | if (!err) { 56 | var command = options.runScript ? ("npm run " + options.runScript) : 57 | options.command ? options.command : ""; 58 | 59 | if (options.verbose) { 60 | var stat = fs.statSync(path); 61 | 62 | console.log(INFO + "|﹏o )з !? " + CLR + path + " (size:" + stat.size + ")"); 63 | console.log(INFO + "|﹏・)っ " + CLR + command); 64 | } 65 | cp.exec(command, function(err, stdout, stderr) { 66 | if (err) { 67 | if (options.verbose) { 68 | console.log(ERR + "|﹏<)з error. " + CLR); 69 | console.log(stdout.split("\n").map(function(line) { 70 | return ERR + "| " + CLR + line; 71 | }).join("\n")); 72 | } 73 | } else { 74 | if (options.verbose) { 75 | console.log(INFO + "|◇・ミ) ok! " + CLR); 76 | } 77 | } 78 | }); 79 | } 80 | }); 81 | 82 | function _parseCommandLineOptions(argv, options) { 83 | for (var i = 0, iz = argv.length; i < iz; ++i) { 84 | switch (argv[i]) { 85 | case "-h": 86 | case "--help": options.help = true; break; 87 | case "-v": 88 | case "--verbose": options.verbose = true; break; 89 | case "--delay": options.delay = argv[++i]; break; 90 | case "--run": 91 | case "--action": options.runScript = argv[++i]; break; 92 | case "--command": options.command = argv[++i]; break; 93 | default: 94 | var path = argv[i]; 95 | 96 | if (fs.existsSync(path) && fs.statSync(path).isFile()) { 97 | if (options.source.indexOf(path) < 0) { // avoid duplicate 98 | options.source.push(path); 99 | } 100 | } else if (fs.existsSync(path) && fs.statSync(path).isDirectory()) { 101 | path = path.replace(/\/+$/, "") + "/"; // supply tail slash. "path" -> "path/" 102 | 103 | if (options.source.indexOf(path) < 0) { // avoid duplicate 104 | options.source.push(path); 105 | } 106 | } else { 107 | console.log(ERR + "invalid path: " + path + CLR); 108 | } 109 | } 110 | } 111 | return options; 112 | } 113 | 114 | function _multiline(fn) { // @arg Function: 115 | // @ret String: 116 | return (fn + "").split("\n").slice(1, -1).join("\n"); 117 | } 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | // --- dependency modules ---------------------------------- 131 | // --- define / local variables ---------------------------- 132 | //var _runOnNode = "process" in global; 133 | //var _runOnWorker = "WorkerLocation" in global; 134 | //var _runOnBrowser = "document" in global; 135 | 136 | // --- class / interfaces ---------------------------------- 137 | function Watch(paths, // @arg PathArray 138 | options, // @arg Object - { delay, action, verbose, ... } 139 | callback) { // @arg Function - callback(err:Error):void 140 | //{@dev 141 | _if(!Array.isArray(paths), "invalid Watch(paths)"); 142 | _if(!_isObject(options), "invalid Watch(,options)"); 143 | _if(!_isFunction(callback), "invalid Watch(,,callback)"); 144 | //}@dev 145 | 146 | var that = this; 147 | 148 | this._options = options || {}; 149 | 150 | paths.forEach(function(path) { 151 | if (_isFile(path)) { 152 | if (this._options.verbose) { 153 | var stat = fs.statSync(path); 154 | console.log(INFO + "|◇・)з " + CLR + "I'm watching " + path + " (size:" + stat.size + ")"); 155 | } 156 | Watch_file(that, path, function() { 157 | callback(null, path); 158 | }); 159 | /* 160 | } else if (_isDir(path)) { 161 | if (this._options.verbose) { 162 | console.log("|◇・)зstart watch..."); 163 | } 164 | Watch_dir(that, path, function(diff) { // { path: { dir, size, mtime }, ... } 165 | callback(null, diff); 166 | }, options); 167 | */ 168 | } 169 | }); 170 | } 171 | 172 | // --- implements ------------------------------------------ 173 | function Watch_file(that, // @arg this 174 | watchFilePath, // @arg String - watch file path 175 | callback) { // @arg Function - callback(null):void 176 | var timerID = 0; 177 | 178 | fs.watchFile(watchFilePath, _watchdogCallback); 179 | 180 | function _watchdogCallback() { 181 | // event throttling 182 | if (timerID) { 183 | clearTimeout(timerID); timerID = 0; 184 | } 185 | timerID = setTimeout(function() { 186 | clearTimeout(timerID); timerID = 0; 187 | 188 | callback(null); 189 | }, that._options.delay); 190 | } 191 | } 192 | 193 | /* 194 | function Watch_dir(that, // @arg this 195 | watchRoorDir, // @arg String - watch root dir 196 | callback, // @arg Function - callback(diff:Object):void 197 | options) { // @arg Object - { ... } 198 | // diff - Object: { path: { dir, size, mtime }, ... } 199 | var timerID = 0; 200 | var keepDirTrees = Watch_scanDir(watchRoorDir, options); // { dirs, files } 201 | 202 | for (var path in keepDirTrees.dirs) { 203 | if (that._options.verbose) { 204 | console.log(INFO + " watch target: " + CLR + path + "/"); 205 | } 206 | fs.watch(path, _watchdogCallback); 207 | } 208 | 209 | function _watchdogCallback() { 210 | if (timerID) { 211 | clearTimeout(timerID); timerID = 0; 212 | } 213 | 214 | // -> sleep(1000) 215 | // -> scanDir(watchRootDir) 216 | // -> get diff 217 | // -> callback(diff) 218 | // -> sleep... 219 | 220 | timerID = setTimeout(function() { 221 | var currentDirTrees = Watch_scanDir(watchRoorDir, options); // { dirs, files } 222 | var diff = _diff(currentDirTrees, keepDirTrees); // { path: { dir, size, mtime }, ... } 223 | 224 | keepDirTrees = currentDirTrees; 225 | 226 | clearTimeout(timerID); timerID = 0; 227 | 228 | callback(diff); 229 | }, that._options.delay); 230 | } 231 | 232 | function _diff(curt, // @arg Object - current dir tree. { dirs, files } 233 | last) { // @arg Object - last dir tree. { dirs, files } 234 | // @ret Object - diff dir tree. { path: { dir, size, mtime }, ... } 235 | var result = {}; 236 | 237 | for (var path in curt.files) { 238 | if ( !_match( path, curt.files[path], last.files[path] ) ) { 239 | result[path] = curt.files[path]; 240 | } 241 | } 242 | return result; 243 | } 244 | 245 | function _match(path, 246 | a, // @arg Object - { dir, size, mtime } 247 | b) { // @arg Object - { dir, size, mtime } 248 | if (a && b) { 249 | if (a.dir === b.dir) { 250 | if (a.size === b.size) { 251 | if (a.mtime === b.mtime) { 252 | return true; 253 | } 254 | } 255 | } 256 | if (that._options.verbose) { 257 | console.log(WARN + " changed: " + CLR + path); 258 | } 259 | } 260 | return false; 261 | } 262 | } 263 | */ 264 | 265 | /* 266 | function Watch_scanDir(scanRootDir, // @arg String - scan root dir 267 | options) { // @arg Object - { ... } 268 | // @ret Object - { dirs: {}, files: {} } 269 | // @options.dirs Object - { dir:Boolean, size:Intger, mtime:Integre } 270 | // @options.files Object - { dir:Boolean, size:Intger, mtime:Integre } 271 | var result = { dirs: {}, files: {} }; 272 | var stat = fs.statSync(scanRootDir); 273 | var ignoreDir = options.ignoreDir || []; 274 | var found = false; 275 | 276 | if ( stat.isDirectory() ) { 277 | // found .watchignore ? 278 | if (ignoreDir.length) { 279 | found = ignoreDir.some(function(value) { 280 | return _isFile(scanRootDir + value); 281 | }); 282 | } 283 | if (found) { 284 | // ignore dir 285 | } else { 286 | result.dirs[scanRootDir] = { 287 | dir: true, 288 | size: stat.size, 289 | mtime: +stat.mtime 290 | }; 291 | _readDir(result, scanRootDir, options); 292 | } 293 | } 294 | return result; 295 | } 296 | */ 297 | 298 | /* 299 | function _readDir(result, // @arg Object - { dirs: {}, files: {} } 300 | dir, // @arg DirString 301 | options) { // @arg Object - { ... } 302 | // @recursive 303 | var fileList = fs.readdirSync(dir); 304 | var ignoreDir = options.ignoreDir || []; 305 | var ignoreFileNamePostFix = options.ignoreFileNamePostFix || []; 306 | 307 | Sort_nat(fileList).forEach(function(fname) { 308 | var path = dir + fname; 309 | var stat = fs.statSync(path); 310 | var found = false; 311 | 312 | if ( stat.isFile() ) { 313 | if (ignoreFileNamePostFix.length) { 314 | found = ignoreFileNamePostFix.some(function(value) { 315 | return path.lastIndexOf(value) === path.length - value.length; 316 | }); 317 | } 318 | if (found) { 319 | // found *.min.js 320 | } else { 321 | result.files[path] = { dir: false, size: stat.size, mtime: +stat.mtime }; 322 | } 323 | } else if ( stat.isDirectory() ) { 324 | path += "/"; 325 | // found .watchignore 326 | if (ignoreDir.length) { 327 | found = ignoreDir.some(function(value) { 328 | return _isFile(path + value); 329 | }); 330 | } 331 | 332 | if (found) { 333 | // ignore dir 334 | } else { 335 | result.dirs[path] = { dir: true, size: stat.size, mtime: +stat.mtime }; 336 | _readDir(result, path, options); // recursive call 337 | } 338 | } 339 | }); 340 | } 341 | */ 342 | 343 | function _isFile(path) { // @arg String 344 | // @ret Boolean 345 | return fs.existsSync(path) && fs.statSync(path).isFile(); 346 | } 347 | 348 | /* 349 | function _isDir(path) { // @arg String 350 | // @ret Boolean 351 | return fs.existsSync(path) && fs.statSync(path).isDirectory(); 352 | } 353 | */ 354 | 355 | /* 356 | // copy from Sort.js 357 | function Sort_nat(source, // @arg StringArray - source. ["abc100", "abc1", "abc10"] 358 | ignoreCase) { // @arg Boolean = false - true is case-insensitive 359 | // @ret StringArray - sorted array. ["abc1", "abc10", "abc100"] 360 | // @desc nat sort 361 | //{@dev 362 | _if(!Array.isArray(source), "Sort.nat(source)"); 363 | _if(ignoreCase !== undefined && 364 | typeof ignoreCase !== "boolean", "Sort.nat(,ignoreCase)"); 365 | //}@dev 366 | 367 | function toNumberArray(str) { 368 | return str.split(/(\d+)/).reduce(function(prev, next) { 369 | if (next !== "") { 370 | if (isNaN(next)) { 371 | next.split("").forEach(function(v) { 372 | prev.push( v.charCodeAt(0) ); 373 | }); 374 | } else { 375 | prev.push(+next); 376 | } 377 | } 378 | return prev; 379 | }, []); 380 | } 381 | 382 | var cache = {}; // { keyword: [number, ...], ... } 383 | 384 | return source.sort(function(a, b) { 385 | var aa, bb; 386 | 387 | if (a in cache) { 388 | aa = cache[a]; 389 | } else { 390 | cache[a] = aa = toNumberArray( ignoreCase ? a.toLowerCase() : a ); 391 | } 392 | if (b in cache) { 393 | bb = cache[b]; 394 | } else { 395 | cache[b] = bb = toNumberArray( ignoreCase ? b.toLowerCase() : b ); 396 | } 397 | var x = 0, y = 0, i = 0, iz = aa.length; 398 | 399 | for (; i < iz; ++i) { 400 | x = aa[i] || 0; 401 | y = bb[i] || 0; 402 | if (x !== y) { 403 | return x - y; 404 | } 405 | } 406 | return a.length - b.length; 407 | }); 408 | } 409 | */ 410 | 411 | // --- validate / assertions ------------------------------- 412 | //{@dev 413 | //function $valid(val, fn, hint) { if (global["Valid"]) { global["Valid"](val, fn, hint); } } 414 | //function $type(obj, type) { return global["Valid"] ? global["Valid"].type(obj, type) : true; } 415 | //function $keys(obj, str) { return global["Valid"] ? global["Valid"].keys(obj, str) : true; } 416 | //function $some(val, str, ignore) { return global["Valid"] ? global["Valid"].some(val, str, ignore) : true; } 417 | //function $args(fn, args) { if (global["Valid"]) { global["Valid"].args(fn, args); } } 418 | //}@dev 419 | 420 | //{@dev 421 | function _isFunction(target) { 422 | return target !== undefined && (typeof target === "function"); 423 | } 424 | function _isObject(target) { 425 | return target && (target.constructor === ({}).constructor); 426 | } 427 | function _if(booleanValue, errorMessageString) { 428 | if (booleanValue) { 429 | throw new Error(errorMessageString); 430 | } 431 | } 432 | //}@dev 433 | 434 | 435 | })((this || 0).self || global); 436 | 437 | 438 | -------------------------------------------------------------------------------- /run/wiki.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require("fs"); 4 | var cp = require("child_process"); 5 | var json = JSON.parse(fs.readFileSync("./package.json", "utf8")); 6 | 7 | //console.log("open " + json.url + "/wiki/"); 8 | 9 | cp.exec("open " + json.url + "/wiki/"); 10 | 11 | --------------------------------------------------------------------------------