utility2
the zero-dependency, swiss-army-knife utility for building, testing, and deploying webapps
live web demo




git-branch : | master | beta | alpha |
---|
test-server-github : |  |  |  |
test-server-heroku : |  |  |  |
test-report : |  |  |  |
coverage : |  |  |  |
build-artifacts : |  |  |  |


table of contents
- cdn download
- documentation
- quickstart standalone app
- quickstart example.js
- extra screenshots
- package.json
- changelog of last 50 commits
- internal build script
- misc
cdn download
documentation
cli help

api doc

todo
- update function buildLib to auto-normalize local2-function
- update jslint-function jslintAndPrint to validate sorted vars
- update jslint-function jslintAndPrint to validate 3 or more continuous-newlines
- add default testCase _testCase_cliRun_help
- merge class _http.IncomingMessage -> _http.ServerResponse
- add test-coverage for function ajaxCrawl
- integrate db-lite and github-crud into a cloud-based db on github
- add server stress-test using electron
- none
changelog 2018.9.8
- npm publish 2018.9.8
- prepare for jslint v2018.05.14
- add shell-command shGitDateCommitted, shDiffRaw
- add file lib.istanbul.raw.js, lib.jslint.raw.js, lib.marked.raw.js, lib.uglifyjs.raw.js
- update function fsReadFileOrEmptyStringSync with 'json' options to auto JSON.parse file or return null
- update function buildLib to include top-level comment-description
- rename template assetsDict['/assets.lib.template.js'] -> assetsDict['/assets.my\_app.template.js']
- update function testRunDefault to suppress console.error in coverage-mode
- rename response.headers -> response.responseHeaders
- make browser-mocked client-request <-> server-response asynchronous
- revamp Buffer helper-functions
- merge nodejs-mock of XMLHttpRequest into function ajax
- none
this package requires
quickstart standalone app
to run this example, follow the instruction in the script below
# example.sh
# this shell script will download and run a web-demo of utility2 as a standalone app
# 1. download standalone app
curl -O https://kaizhu256.github.io/node-utility2/build..beta..travis-ci.org/app/assets.app.js
# 2. run standalone app
PORT=8081 node ./assets.app.js
# 3. open a browser to http://127.0.0.1:8081 and play with the web-demo
# 4. edit file assets.app.js to suit your needs
output from browser

output from shell

quickstart example.js

to run this example, follow the instruction in the script below
(function () {
'use strict';
var local;
(function () {
local = {};
local.isBrowser = typeof window === "object" &&
typeof window.XMLHttpRequest === "function" &&
window.document &&
typeof window.document.querySelectorAll === "function";
local.global = local.isBrowser
? window
: global;
local = local.global.utility2_rollup || (local.isBrowser
? local.global.utility2_utility2
: require('utility2'));
local.global.local = local;
local.testRunServer(local);
local.assetsDict['/assets.hello.txt'] = 'hello\ud83d\ude01\u0020\n';
local.assetsDict['/assets.index.template.html'] = '';
}());
(function () {
local.testCase_ajax_200 = function (options, onError) {
if (!local.isBrowser) {
onError(null, options);
return;
}
options = {};
local.ajax({ url: 'assets.hello.txt' }, function (error, xhr) {
local.tryCatchOnError(function () {
local.assert(!error, error);
options.data = xhr.responseText;
local.assert(options.data === 'hello\ud83d\ude01\u0020\n', options.data);
onError();
}, onError);
});
};
local.testCase_ajax_404 = function (options, onError) {
if (!local.isBrowser) {
onError(null, options);
return;
}
options = {};
local.ajax({ url: '/undefined' }, function (error) {
local.tryCatchOnError(function () {
local.assert(error, error);
options.statusCode = error.statusCode;
local.assert(options.statusCode === 404, options.statusCode);
onError();
}, onError);
});
};
local.testCase_webpage_default = function (options, onError) {
if (local.env.npm_config_mode_test_fast || local.isBrowser) {
onError(null, options);
return;
}
options = { modeCoverageMerge: true, url: local.serverLocalHost + '?modeTest=1' };
local.browserTest(options, onError);
};
}());
(function () {
if (!local.isBrowser) {
return;
}
local.testRunBrowser = function (event) {
if (!event || (event &&
event.currentTarget &&
event.currentTarget.className &&
event.currentTarget.className.includes &&
event.currentTarget.className.includes('onreset'))) {
Array.from(document.querySelectorAll(
'body > .resettable'
)).forEach(function (element) {
switch (element.tagName) {
case 'INPUT':
case 'TEXTAREA':
element.value = '';
break;
default:
element.textContent = '';
}
});
}
switch (event && event.currentTarget && event.currentTarget.id) {
case 'testRunButton1':
if (document.querySelector('#testReportDiv1').style.maxHeight === '0px') {
local.uiAnimateSlideDown(document.querySelector('#testReportDiv1'));
document.querySelector('#testRunButton1').textContent = 'hide internal test';
local.modeTest = 1;
local.testRunDefault(local);
} else {
local.uiAnimateSlideUp(document.querySelector('#testReportDiv1'));
document.querySelector('#testRunButton1').textContent = 'run internal test';
}
break;
case 'testRunButton2':
local.modeTest = 1;
local.testRunDefault(local);
break;
default:
if (location.href.indexOf("modeTest=") >= 0) {
return;
}
try {
document.querySelector('#outputJsonStringifyPre1').textContent = '';
document.querySelector('#outputJsonStringifyPre1').textContent =
local.jsonStringifyOrdered(
JSON.parse(document.querySelector('#inputTextareaEval1').value),
null,
4
);
} catch (ignore) {
}
local.jslint.errorText = '';
if (document.querySelector('#inputTextareaEval1').value
.indexOf('/*jslint') >= 0) {
local.jslint.jslintAndPrint(
document.querySelector('#inputTextareaEval1').value,
'inputTextareaEval1.js'
);
}
document.querySelector('#outputJslintPre1').textContent =
local.jslint.errorText
.replace((/\u001b\[\d*m/g), '')
.trim();
try {
delete local.global.__coverage__['/inputTextareaEval1.js'];
} catch (ignore) {
}
try {
document.querySelector('#outputTextarea1').value =
local.istanbul.instrumentSync(
document.querySelector('#inputTextareaEval1').value,
'/inputTextareaEval1.js'
);
eval(document.querySelector('#outputTextarea1').value);
document.querySelector('#coverageReportDiv1').innerHTML =
local.istanbul.coverageReportCreate({
coverage: window.__coverage__
});
} catch (errorCaught) {
console.error(errorCaught);
}
}
if (document.querySelector('#inputTextareaEval1') && (!event || (event &&
event.currentTarget &&
event.currentTarget.className &&
event.currentTarget.className.includes &&
event.currentTarget.className.includes('oneval')))) {
try {
eval(document.querySelector('#inputTextareaEval1').value);
} catch (errorCaught) {
console.error(errorCaught);
}
}
};
['error', 'log'].forEach(function (key) {
console[key + '_original'] = console[key + '_original'] || console[key];
console[key] = function () {
var element;
console[key + '_original'].apply(console, arguments);
element = document.querySelector('#outputStdoutTextarea1');
if (!element) {
return;
}
element.value += Array.from(arguments).map(function (arg) {
return typeof arg === 'string'
? arg
: JSON.stringify(arg, null, 4);
}).join(' ').replace((/\u001b\[\d*m/g), '') + '\n';
element.scrollTop = element.scrollHeight;
};
});
['change', 'click', 'keyup'].forEach(function (event) {
Array.from(document.querySelectorAll('.on' + event)).forEach(function (element) {
element.addEventListener(event, local.testRunBrowser);
});
});
local.testRunBrowser();
}());
(function () {
if (local.isBrowser) {
return;
}
module.exports = local;
local.buffer = require('buffer');
local.child_process = require('child_process');
local.cluster = require('cluster');
local.crypto = require('crypto');
local.dgram = require('dgram');
local.dns = require('dns');
local.domain = require('domain');
local.events = require('events');
local.fs = require('fs');
local.http = require('http');
local.https = require('https');
local.net = require('net');
local.os = require('os');
local.path = require('path');
local.querystring = require('querystring');
local.readline = require('readline');
local.repl = require('repl');
local.stream = require('stream');
local.string_decoder = require('string_decoder');
local.timers = require('timers');
local.tls = require('tls');
local.tty = require('tty');
local.url = require('url');
local.util = require('util');
local.vm = require('vm');
local.zlib = require('zlib');
local.assetsDict = local.assetsDict || {};
[
'assets.index.template.html',
'assets.swgg.swagger.json',
'assets.swgg.swagger.server.json'
].forEach(function (file) {
file = '/' + file;
local.assetsDict[file] = local.assetsDict[file] || '';
if (local.fs.existsSync(local.__dirname + file)) {
local.assetsDict[file] = local.fs.readFileSync(
local.__dirname + file,
'utf8'
);
}
});
local.assetsDict['/assets.index.template.html'] = '\
<!doctype html>\n\
<html lang="en">\n\
<head>\n\
<meta charset="utf-8">\n\
<meta name="viewport" content="width=device-width, initial-scale=1">\n\
<!-- "assets.utility2.template.html" -->\n\
<title>{{env.npm_package_name}} ({{env.npm_package_version}})</title>\n\
<style>\n\
/* jslint-utility2 */\n\
/*csslint\n\
*/\n\
/* jslint-ignore-begin */\n\
*,\n\
*:after,\n\
*:before {\n\
box-sizing: border-box;\n\
}\n\
/* jslint-ignore-end */\n\
@keyframes uiAnimateShake {\n\
0%, 50% {\n\
transform: translateX(10px);\n\
}\n\
25%, 75% {\n\
transform: translateX(-10px);\n\
}\n\
100% {\n\
transform: translateX(0);\n\
}\n\
}\n\
@keyframes uiAnimateSpin {\n\
0% {\n\
transform: rotate(0deg);\n\
}\n\
100% {\n\
transform: rotate(360deg);\n\
}\n\
}\n\
a {\n\
overflow-wrap: break-word;\n\
}\n\
body {\n\
background: #eef;\n\
font-family: Arial, Helvetica, sans-serif;\n\
margin: 0 40px;\n\
}\n\
body > div,\n\
body > form > div,\n\
body > form > input,\n\
body > form > pre,\n\
body > form > textarea,\n\
body > form > .button,\n\
body > input,\n\
body > pre,\n\
body > textarea,\n\
body > .button {\n\
margin-bottom: 20px;\n\
}\n\
body > form > input,\n\
body > form > .button,\n\
body > input,\n\
body > .button {\n\
width: 20rem;\n\
}\n\
body > form > textarea,\n\
body > textarea {\n\
height: 10rem;\n\
width: 100%;\n\
}\n\
body > textarea[readonly] {\n\
background: #ddd;\n\
}\n\
code,\n\
pre,\n\
textarea {\n\
font-family: Consolas, Menlo, monospace;\n\
font-size: small;\n\
}\n\
pre {\n\
overflow-wrap: break-word;\n\
white-space: pre-wrap;\n\
}\n\
textarea {\n\
overflow: auto;\n\
white-space: pre;\n\
}\n\
.button {\n\
background-color: #fff;\n\
border: 1px solid;\n\
border-bottom-color: rgb(186, 186, 186);\n\
border-left-color: rgb(209, 209, 209);\n\
border-radius: 4px;\n\
border-right-color: rgb(209, 209, 209);\n\
border-top-color: rgb(216, 216, 216);\n\
color: #00d;\n\
cursor: pointer;\n\
display: inline-block;\n\
font-family: Arial, Helvetica, sans-serif;\n\
font-size: 12px;\n\
font-style: normal;\n\
font-weight: normal;\n\
margin: 0;\n\
padding: 2px 7px 3px 7px;\n\
text-align: center;\n\
text-decoration: underline;\n\
}\n\
.colorError {\n\
color: #d00;\n\
}\n\
.uiAnimateShake {\n\
animation-duration: 500ms;\n\
animation-name: uiAnimateShake;\n\
}\n\
.uiAnimateSlide {\n\
overflow-y: hidden;\n\
transition: max-height ease-in 250ms, min-height ease-in 250ms, padding-bottom ease-in 250ms, padding-top ease-in 250ms;\n\
}\n\
.utility2FooterDiv {\n\
text-align: center;\n\
}\n\
.zeroPixel {\n\
border: 0;\n\
height: 0;\n\
margin: 0;\n\
padding: 0;\n\
width: 0;\n\
}\n\
</style>\n\
</head>\n\
<body>\n\
<div id="ajaxProgressDiv1" style="background: #d00; height: 2px; left: 0; margin: 0; padding: 0; position: fixed; top: 0; transition: background 500ms, width 1500ms; width: 0%; z-index: 1;"></div>\n\
<div class="uiAnimateSpin" style="animation: uiAnimateSpin 2s linear infinite; border: 5px solid #999; border-radius: 50%; border-top: 5px solid #7d7; display: none; height: 25px; vertical-align: middle; width: 25px;"></div>\n\
<a class="zeroPixel" download="db.persistence.json" href="" id="dbExportA1"></a>\n\
<input class="zeroPixel" id="dbImportInput1" type="file">\n\
<script>\n\
/* jslint-utility2 */\n\
/*jslint\n\
bitwise: true,\n\
browser: true,\n\
maxerr: 4,\n\
maxlen: 100,\n\
node: true,\n\
nomen: true,\n\
regexp: true,\n\
stupid: true\n\
*/\n\
// init domOnEventWindowOnloadTimeElapsed\n\
(function () {\n\
/*\n\
* this function will measure and print the time-elapsed for window.onload\n\
*/\n\
"use strict";\n\
if (window.domOnEventWindowOnloadTimeElapsed) {\n\
return;\n\
}\n\
window.domOnEventWindowOnloadTimeElapsed = Date.now() + 100;\n\
window.addEventListener("load", function () {\n\
setTimeout(function () {\n\
window.domOnEventWindowOnloadTimeElapsed = Date.now() -\n\
window.domOnEventWindowOnloadTimeElapsed;\n\
console.error("domOnEventWindowOnloadTimeElapsed = " +\n\
window.domOnEventWindowOnloadTimeElapsed);\n\
}, 100);\n\
});\n\
}());\n\
// init timerIntervalAjaxProgressUpdate\n\
(function () {\n\
/*\n\
* this function will increment the ajax-progress-bar until the webpage has loaded\n\
*/\n\
"use strict";\n\
var ajaxProgressDiv1,\n\
ajaxProgressState,\n\
ajaxProgressUpdate;\n\
if (window.timerIntervalAjaxProgressUpdate || !document.querySelector("#ajaxProgressDiv1")) {\n\
return;\n\
}\n\
ajaxProgressDiv1 = document.querySelector("#ajaxProgressDiv1");\n\
setTimeout(function () {\n\
ajaxProgressDiv1.style.width = "25%";\n\
});\n\
ajaxProgressState = 0;\n\
ajaxProgressUpdate = (window.local &&\n\
window.local.ajaxProgressUpdate) || function () {\n\
ajaxProgressDiv1.style.width = "100%";\n\
setTimeout(function () {\n\
ajaxProgressDiv1.style.background = "transparent";\n\
setTimeout(function () {\n\
ajaxProgressDiv1.style.width = "0%";\n\
}, 500);\n\
}, 1500);\n\
};\n\
window.timerIntervalAjaxProgressUpdate = setInterval(function () {\n\
ajaxProgressState += 1;\n\
ajaxProgressDiv1.style.width = Math.max(\n\
100 - 75 * Math.exp(-0.125 * ajaxProgressState),\n\
ajaxProgressDiv1.style.width.slice(0, -1) | 0\n\
) + "%";\n\
}, 1000);\n\
window.addEventListener("load", function () {\n\
clearInterval(window.timerIntervalAjaxProgressUpdate);\n\
ajaxProgressUpdate();\n\
});\n\
}());\n\
// init domOnEventSelectAllWithinPre\n\
(function () {\n\
/*\n\
* this function will limit select-all within <pre tabIndex="0"> elements\n\
* https://stackoverflow.com/questions/985272/selecting-text-in-an-element-akin-to-highlighting-with-your-mouse\n\
*/\n\
"use strict";\n\
if (window.domOnEventSelectAllWithinPre) {\n\
return;\n\
}\n\
window.domOnEventSelectAllWithinPre = function (event) {\n\
var range, selection;\n\
if (event &&\n\
event.key === "a" &&\n\
(event.ctrlKey || event.metaKey) &&\n\
event.target.closest("pre")) {\n\
range = document.createRange();\n\
range.selectNodeContents(event.target.closest("pre"));\n\
selection = window.getSelection();\n\
selection.removeAllRanges();\n\
selection.addRange(range);\n\
event.preventDefault();\n\
}\n\
};\n\
document.addEventListener("keydown", window.domOnEventSelectAllWithinPre);\n\
}());\n\
</script>\n\
<h1>\n\
<!-- utility2-comment\n\
<a\n\
{{#if env.npm_package_homepage}}\n\
href="{{env.npm_package_homepage}}"\n\
{{/if env.npm_package_homepage}}\n\
target="_blank"\n\
>\n\
utility2-comment -->\n\
{{env.npm_package_name}} ({{env.npm_package_version}})\n\
<!-- utility2-comment\n\
</a>\n\
utility2-comment -->\n\
</h1>\n\
<h3>{{env.npm_package_description}}</h3>\n\
<!-- utility2-comment\n\
<a class="button" download href="assets.app.js">download standalone app</a><br>\n\
<button class="zeroPixel" id="testRunButton1"></button>\n\
<button class="button onclick onreset" id="testRunButton2">run internal test</button><br>\n\
utility2-comment -->\n\
\n\
\n\
\n\
<label>edit or paste script below to cover and test</label>\n\
<textarea class="oneval onkeyup onreset" id="inputTextareaEval1">\n\
// remove comment below to disable jslint\n\
/*jslint\n\
browser: true,\n\
es6: true\n\
*/\n\
/*global window*/\n\
(function () {\n\
"use strict";\n\
var testCaseDict;\n\
testCaseDict = {};\n\
testCaseDict.modeTest = 1;\n\
\n\
// comment this testCase to disable the failed assertion demo\n\
testCaseDict.testCase_failed_assertion_demo = function (options, onError) {\n\
/*\n\
* this function will demo a failed assertion test\n\
*/\n\
// jslint-hack\n\
window.utility2.nop(options);\n\
window.utility2.assert(false, "this is a failed assertion demo");\n\
onError();\n\
};\n\
\n\
testCaseDict.testCase_passed_ajax_demo = function (options, onError) {\n\
/*\n\
* this function will demo a passed ajax test\n\
*/\n\
var data;\n\
options = {url: "/"};\n\
// test ajax request for main-page "/"\n\
window.utility2.ajax(options, function (error, xhr) {\n\
try {\n\
// validate no error occurred\n\
window.utility2.assert(!error, error);\n\
// validate "200 ok" status\n\
window.utility2.assert(xhr.statusCode === 200, xhr.statusCode);\n\
// validate non-empty data\n\
data = xhr.responseText;\n\
window.utility2.assert(data && data.length > 0, data);\n\
onError();\n\
} catch (errorCaught) {\n\
onError(errorCaught);\n\
}\n\
});\n\
};\n\
\n\
window.utility2.testRunDefault(testCaseDict);\n\
}());\n\
</textarea>\n\
<pre id="outputJsonStringifyPre1" tabindex="0"></pre>\n\
<pre class= "colorError" id="outputJslintPre1" tabindex="0"></pre>\n\
<label>instrumented-code</label>\n\
<textarea class="resettable" id="outputTextarea1" readonly></textarea>\n\
<label>stderr and stdout</label>\n\
<textarea class="resettable" id="outputStdoutTextarea1" readonly></textarea>\n\
<div class="resettable" id="testReportDiv1"></div>\n\
<div class="resettable" id="coverageReportDiv1"></div>\n\
<!-- utility2-comment\n\
{{#if isRollup}}\n\
<script src="assets.app.js"></script>\n\
{{#unless isRollup}}\n\
utility2-comment -->\n\
<script src="assets.utility2.lib.istanbul.js"></script>\n\
<script src="assets.utility2.lib.jslint.js"></script>\n\
<script src="assets.utility2.lib.db.js"></script>\n\
<script src="assets.utility2.lib.marked.js"></script>\n\
<script src="assets.utility2.lib.sjcl.js"></script>\n\
<script src="assets.utility2.lib.uglifyjs.js"></script>\n\
<script src="assets.utility2.js"></script>\n\
<script>window.utility2_onReadyBefore.counter += 1;</script>\n\
<script src="jsonp.utility2.stateInit?callback=window.utility2.stateInit"></script>\n\
<script src="assets.example.js"></script>\n\
<script src="assets.test.js"></script>\n\
<script>window.utility2_onReadyBefore();</script>\n\
<!-- utility2-comment\n\
{{/if isRollup}}\n\
utility2-comment -->\n\
<div class="utility2FooterDiv">\n\
[ this app was created with\n\
<a href="https://github.com/kaizhu256/node-utility2" target="_blank">utility2</a>\n\
]\n\
</div>\n\
</body>\n\
</html>\n\
';
local.assetsDict['/assets.utility2.js'] =
local.assetsDict['/assets.utility2.js'] ||
local.fs.readFileSync(local.__dirname + '/lib.utility2.js', 'utf8'
).replace((/^#!\//), '// ');
local.assetsDict['/'] =
local.assetsDict['/assets.example.html'] =
local.assetsDict['/index.html'] =
local.assetsDict['/assets.index.template.html']
.replace((/\{\{env\.(\w+?)\}\}/g), function (match0, match1) {
switch (match1) {
case 'npm_package_description':
return 'the greatest app in the world!';
case 'npm_package_name':
return 'utility2';
case 'npm_package_nameLib':
return 'utility2';
case 'npm_package_version':
return '0.0.1';
default:
return match0;
}
});
if (module !== require.main || local.global.utility2_rollup) {
return;
}
local.assetsDict['/assets.example.js'] =
local.assetsDict['/assets.example.js'] ||
local.fs.readFileSync(__filename, 'utf8');
local.assetsDict['/favicon.ico'] = local.assetsDict['/favicon.ico'] || '';
if (Number(process.env.npm_config_timeout_exit)) {
setTimeout(process.exit, Number(process.env.npm_config_timeout_exit));
}
if (local.global.utility2_serverHttp1) {
return;
}
process.env.PORT = process.env.PORT || '8081';
console.error('server starting on port ' + process.env.PORT);
local.http.createServer(function (request, response) {
request.urlParsed = local.url.parse(request.url);
if (local.assetsDict[request.urlParsed.pathname] !== undefined) {
response.end(local.assetsDict[request.urlParsed.pathname]);
return;
}
response.statusCode = 404;
response.end();
}).listen(process.env.PORT);
}());
}());
output from browser

output from shell

-
https://kaizhu256.github.io/node-utility2/build/screenshot.buildCi.browser.%252Ftmp%252Fbuild%252Fapidoc.html.png

-
https://kaizhu256.github.io/node-utility2/build/screenshot.buildCi.browser.%252Ftmp%252Fbuild%252Fcoverage.lib.html.png

-
https://kaizhu256.github.io/node-utility2/build/screenshot.buildCi.browser.%252Ftmp%252Fbuild%252Ftest-report.html.png

-
https://kaizhu256.github.io/node-utility2/build/screenshot.deployGithub.browser.%252Fnode-utility2%252Fbuild%252Fapp%252Fassets.swgg.html.png

-
https://kaizhu256.github.io/node-utility2/build/screenshot.deployGithub.browser.%252Fnode-utility2%252Fbuild%252Fapp.png

-
https://kaizhu256.github.io/node-utility2/build/screenshot.deployGithubTest.browser.%252Fnode-utility2%252Fbuild%252Fapp.png

-
https://kaizhu256.github.io/node-utility2/build/screenshot.deployHeroku.browser.%252Fassets.swgg.html.png

-
https://kaizhu256.github.io/node-utility2/build/screenshot.deployHeroku.browser.%252F.png

-
https://kaizhu256.github.io/node-utility2/build/screenshot.deployHerokuTest.browser.%252F.png

-
https://kaizhu256.github.io/node-utility2/build/screenshot.npmTest.browser.%252F.png

-
https://kaizhu256.github.io/node-utility2/build/screenshot.testExampleJs.browser.%252F.png

-
https://kaizhu256.github.io/node-utility2/build/screenshot.testExampleSh.browser.%252F.png

package.json
{
"author": "kai zhu <kaizhu256@gmail.com>",
"bin": {
"utility2": "lib.utility2.sh",
"utility2-apidoc": "lib.apidoc.js",
"utility2-db": "lib.db.js",
"utility2-github-crud": "lib.github_crud.js",
"utility2-istanbul": "lib.istanbul.js",
"utility2-jslint": "lib.jslint.js",
"utility2-uglifyjs": "lib.uglifyjs.js"
},
"description": "the zero-dependency, swiss-army-knife utility for building, testing, and deploying webapps",
"devDependencies": {
"electron-lite": "kaizhu256/node-electron-lite#alpha"
},
"engines": {
"node": ">=4.0"
},
"homepage": "https://github.com/kaizhu256/node-utility2",
"keywords": [
"continuous-integration",
"npmdoc",
"npmtest",
"test-coverage",
"travis-ci"
],
"license": "MIT",
"main": "lib.utility2.js",
"name": "utility2",
"nameAliasPublish": "busybox npmtest-lite test-lite",
"nameLib": "utility2",
"nameOriginal": "utility2",
"os": [
"darwin",
"linux"
],
"repository": {
"type": "git",
"url": "https://github.com/kaizhu256/node-utility2.git"
},
"scripts": {
"build-ci": "./npm_scripts.sh",
"env": "env",
"eval": "./npm_scripts.sh",
"heroku-postbuild": "./npm_scripts.sh",
"postinstall": "./npm_scripts.sh",
"start": "./npm_scripts.sh",
"test": "./npm_scripts.sh",
"utility2": "./npm_scripts.sh"
},
"version": "2018.9.8"
}
changelog of last 50 commits

internal build script
# Dockerfile.base
# docker build -f tmp/README.Dockerfile.base -t kaizhu256/node-utility2:base .
# docker build -f "tmp/README.Dockerfile.$DOCKER_TAG" -t "$GITHUB_REPO:$DOCKER_TAG" .
# https://hub.docker.com/_/node/
FROM debian:stable-slim
MAINTAINER kai zhu <kaizhu256@gmail.com>
VOLUME [ \
"/mnt", \
"/root", \
"/tmp", \
"/usr/share/doc", \
"/usr/share/man", \
"/var/cache", \
"/var/lib/apt", \
"/var/log", \
"/var/tmp" \
]
WORKDIR /tmp
# install nodejs
# https://nodejs.org/en/download/package-manager/
RUN (set -e; \
export DEBIAN_FRONTEND=noninteractive; \
apt-get update; \
apt-get install --no-install-recommends -y \
apt-utils \
busybox \
ca-certificates \
curl \
git \
gnupg; \
(busybox --list | xargs -n1 /bin/sh -c 'ln -s /bin/busybox /bin/$0 2>/dev/null' || true); \
curl -#L https://deb.nodesource.com/setup_8.x | /bin/bash -; \
apt-get install -y nodejs; \
(cd /usr/lib && npm install sqlite3@3); \
)
# install electron-lite
# COPY electron-*.zip /tmp
# libasound.so.2: cannot open shared object file: No such file or directory
# libgconf-2.so.4: cannot open shared object file: No such file or directory
# libgtk-x11-2.0.so.0: cannot open shared object file: No such file or directory
# libnss3.so: cannot open shared object file: No such file or directory
# libXss.so.1: cannot open shared object file: No such file or directory
# libXtst.so.6: cannot open shared object file: No such file or directory
RUN (set -e; \
export DEBIAN_FRONTEND=noninteractive; \
apt-get update; \
apt-get install --no-install-recommends -y \
libasound2 \
libgconf-2-4 \
libgtk2.0-0 \
libnss3 \
libxss1 \
libxtst6 \
xvfb; \
rm -f /tmp/.X99-lock && export DISPLAY=:99.0 && (Xvfb "$DISPLAY" &); \
npm install kaizhu256/node-electron-lite#alpha; \
mv node_modules/electron-lite/external /opt/electron; \
ln -fs /opt/electron/electron /bin/electron; \
cd node_modules/electron-lite; \
npm install --unsafe-perm; \
npm test; \
)
# install extra
RUN (set -e; \
export DEBIAN_FRONTEND=noninteractive; \
apt-get update; \
apt-get install --no-install-recommends -y \
ffmpeg \
imagemagick \
nginx-extras \
sqlite3 \
transmission-daemon \
ssh \
vim \
wget; \
)
# Dockerfile.latest
FROM kaizhu256/node-utility2:base
MAINTAINER kai zhu <kaizhu256@gmail.com>
# install utility2
RUN (set -e; \
export DEBIAN_FRONTEND=noninteractive; \
rm -f /tmp/.X99-lock && export DISPLAY=:99.0 && (Xvfb "$DISPLAY" &); \
npm install kaizhu256/node-utility2#alpha; \
cp -a node_modules /; \
cd node_modules/utility2; \
npm install; \
npm test; \
)
# install elasticsearch-lite
RUN (set -e; \
export DEBIAN_FRONTEND=noninteractive; \
mkdir -p /usr/share/man/man1; \
apt-get update; \
apt-get install --no-install-recommends -y \
default-jre; \
rm -f /tmp/.X99-lock && export DISPLAY=:99.0 && (Xvfb "$DISPLAY" &); \
npm install kaizhu256/node-elasticsearch-lite#alpha; \
cp -a node_modules /; \
cd node_modules/elasticsearch-lite; \
npm install; \
npm test; \
)
# Dockerfile.tmp
FROM kaizhu256/node-utility2:base
MAINTAINER kai zhu <kaizhu256@gmail.com>
# install extra
RUN (set -e; \
export DEBIAN_FRONTEND=noninteractive; \
apt-get update; \
apt-get install --no-install-recommends -y \
aptitude \
cmake \
g++ \
make; \
)
# install binaryen
RUN (set -e; \
export DEBIAN_FRONTEND=noninteractive; \
git clone https://github.com/WebAssembly/binaryen.git \
--branch version_31 \
--depth 1; \
cd binaryen; \
cmake .; \
make; \
mv bin /opt/binaryen; \
)
# build_ci.sh
# this shell script will run the build for this package
shBuildCiAfter () {(set -e
#// coverage-hack - test comment handling-behavior
# shDeployCustom
shDeployGithub
shDeployHeroku
shReadmeTest example.sh
# restore $CI_BRANCH
export CI_BRANCH="$CI_BRANCH_OLD"
# docker build
docker --version 2>/dev/null || return
export DOCKER_TAG="$(printf "$CI_BRANCH" | sed -e "s/docker.//")"
# if $DOCKER_TAG is not unique from $CI_BRANCH, then return
if [ "$DOCKER_TAG" = "$CI_BRANCH" ]
then
return
fi
# docker build
docker build -f "tmp/README.Dockerfile.$DOCKER_TAG" -t "$GITHUB_REPO:$DOCKER_TAG" .
# docker test
case "$CI_BRANCH" in
docker.base)
# npm test utility2
for PACKAGE in utility2 "kaizhu256/node-utility2#alpha"
do
docker run "$GITHUB_REPO:$DOCKER_TAG" /bin/sh -c "set -e
curl -Ls https://raw.githubusercontent.com\
/kaizhu256/node-utility2/alpha/lib.utility2.sh > /tmp/lib.utility2.sh
. /tmp/lib.utility2.sh
npm install '$PACKAGE'
cd node_modules/utility2
shBuildInsideDocker
"
done
;;
esac
# https://docs.travis-ci.com/user/docker/#Pushing-a-Docker-Image-to-a-Registry
# docker push
if [ "$DOCKER_PASSWORD" ]
then
docker login -p="$DOCKER_PASSWORD" -u="$DOCKER_USERNAME"
docker push "$GITHUB_REPO:$DOCKER_TAG"
fi
)}
shBuildCiBefore () {(set -e
shNpmTestPublished
shReadmeTest example.js
# screenshot
MODE_BUILD=testExampleJs shBrowserTest \
/tmp/app/tmp/build/coverage.html/app/example.js.html,tmp/build/test-report.html \
screenshot
)}
# run shBuildCi
. ./lib.utility2.sh
shBuildCi
misc