NodeJS
NodeJS basic
What is NodeJS ?
- Node is a runtime environment for executing JavaScript code.
- Non-blocking (asynchronous) architecture.
- It has an event loop with event queue.
- It is good for network-intensive apps, but not good for CPU intensive applications.
- Running on top of the V8 Virtual Machine written by Google, which is also the JavaScript engine in Chrome.
NodeJS Installation
- NodeJS pick the LTS
NodeJS Installation Linux
By the time you are reading this, there might have a newer LTS version already.
export NODEJS=v14.15.1
wget https://nodejs.org/dist/$NODEJS/node-$NODEJS-linux-x64.tar.xz
tar xf node-$NODEJS-linux-x64.tar.xz
sudo mv node-$NODEJS-linux-x64/ /opt
sudo chown -R root.root /opt/node-$NODEJS-linux-x64/
sudo ln -s /opt/node-$NODEJS-linux-x64 /opt/node
Add it to the PATH:
echo "export PATH=\$PATH:/opt/node/bin" >> ~/.bashrc
NodeJS version
- node
$ which node
/opt/node/bin/node
$ node -v
v14.15.1
Hello World
- console
- log
console.log("Hello World");
$ node examples/basic/hello_world.js
Hello World
Comments
- //
console.log("Start here")
// this is a comment
// console.log("This line is not in use")
console.log("Still working") // But comment here
/*
Multi-line comment
console.log("Maybe with code")
*/
console.log("End here")
Start here
Still working
End here
Exercise: Hello World
- The primary goal of this exercise is to make sure you have your environment ready to write more code.
- Create a file called
hello.js
and make it print "Hello World". - Run the code from the command line.
- Run the code from your IDE, if you use one.
- Add some comments to your code and check if you can still run it.
Hello World with sh
Unix-specific issue:
#!/usr/bin/env node
console.log("Hello World");
Make the file executable:
chmod +x examples/basic/hello_world_sh.js
Run it directly
./examples/basic/hello_world_sh.js
Literal Values and types
- typeof
- number
- string
- boolean
console.log(42); // 42
console.log(3.14); // 3.14
console.log("some text"); // some text
console.log('more text'); // more text
console.log("42"); // 42
console.log(true); // true
console.log("true"); // true
console.log('')
console.log(typeof 42); // number
console.log(typeof 3.14); // number
console.log(typeof "text"); // string
console.log(typeof 'text'); // string
console.log(typeof "42"); // string
console.log(typeof true); // boolean
console.log(typeof "true"); // string
Declare variables with let
- let
let x = 19
let y = 23
let res = x + y
console.log(res) // 42
Hello World in function
- function
function sayHello() {
console.log('Hello World')
}
sayHello()
Hello World
Parameter passing to function
function sayHello(name) {
console.log('Hello ' + name)
}
sayHello('Kate')
Hello Kate
for loop
- for
for (let ix = 0; ix < 5; ix++) {
console.log(ix);
}
0
1
2
3
4
Array
var solar = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptunus"]
console.log(solar)
console.log(solar[0])
Command line arguments (argv)
- process
- argv
Throught the process object we can access the command line of our program.
The first value is node
itself. The second value is our code, then come the values from that the user supplied.
console.log(process.argv.length);
console.log(process.argv);
console.log('')
console.log(process.argv[0]);
console.log(process.argv[1]);
console.log(process.argv[2]);
console.log(process.argv[3]);
console.log(process.argv[4]);
$ node argv.js "hello world" Foo
4
[
'/opt/node-v12.14.1-linux-x64/bin/node',
'/home/gabor/work/slides/nodejs/examples/basic/argv.js',
'hello world',
'Foo'
]
/opt/node-v12.14.1-linux-x64/bin/node
/home/gabor/work/slides/nodejs/examples/basic/argv.js
hello world
Foo
undefined
Command line arguments - forEach (argv)
- forEach
Try: node argv_foreach.js Hello my world
process.argv.forEach((val, index) => {
console.log(`${index}: ${val}`);
});
0: /opt/node-v12.14.1-linux-x64/bin/node
1: /home/gabor/work/slides/nodejs/examples/basic/argv_foreach.js
Define function with arrow notation
const sum = (a, b) => a + b;
console.log( sum(2, 3) )
5
setTimeout - delayed execution
- setTimeout
Delayed execution, callback function.
- First we use
setTimeout
to schedule an anonymous function to be executed 1000 ms later. - Then we print "hello" to the console.
- Then, after a second, the functions starts running and prints "world"
setTimeout(function() {
console.log("world");
}, 1000);
console.log("hello");
$ node examples/basic/with_timeout.js
hello
world
setInterval - scheduled execution
-
setInterval
-
setInterval
allows for repeated calls. We can stop this infinite calling using Ctrl-C.
setInterval(function() {
console.log("world");
}, 1000);
console.log("hello");
$ node examples/basic/with_interval.js
hello
world
world
world
^C
clearInterval
-
clearInterval
-
setInterval
-
setTimeout
-
setInterval
returns an identifier that can later be used to stop the scheduled process. -
clearInterval
will stop a scheduled process.
var intervalId = setInterval(function() {
console.log("world");
}, 1000);
setTimeout(function() {
console.log("Calling clearInterval");
clearInterval(intervalId);
}, 3030);
console.log("hello");
$ node examples/basic/with_clearinterval.js
hello
world
world
world
Calling clearInterval
clearTimeout
- clearTimeout
var t3000 = setTimeout(function() {
console.log("Hello 3000");
}, 3000)
var t2000 = setTimeout(function() {
console.log("Hello 2000");
}, 2000)
var t1000 = setTimeout(function() {
console.log("Hello 1000");
clearTimeout(t2000);
console.log("cleared 2000");
}, 1000)
console.log("start")
start
Hello 1000
cleared 2000
Hello 3000
Template literals (template strings) - variable interpolation
let name = 'Kate'
console.log(`Hello ${name}`)
$ node examples/basic/template_literals.js
Hello Kate
Scope of variables and constants
- let
- var
- const
There are several ways to start declaring and using variables and constants.
In general the best is to use the let
keyword.
x = "Joe"
var y = "Jane"
let z = "George"
const w = "nothing"
console.log(x) // Joe
console.log(y) // Jane
console.log(z) // George
console.log(w) // nothing
constant (const)
- const
const pi = 3.14;
console.log(pi);
pi = 3.15;
$ node examples/basic/const.js
3.14
/home/gabor/work/slides/nodejs/examples/basic/const.js:6
pi = 3.15;
^
TypeError: Assignment to constant variable.
at Object.<anonymous> (/home/gabor/work/slides/nodejs/examples/basic/const.js:6:4)
at Module._compile (internal/modules/cjs/loader.js:776:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:829:12)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
var
- var
var x = 1;
console.log(x); // 1
if (true) {
console.log(x); // 1
x = 2;
console.log(x); // 2
}
console.log(x); // 2
var x = 1;
console.log(x); // 1
if (true) {
console.log(x); // 1
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
x = 1;
console.log(x); // 1
if (true) {
console.log(x); // 1
x = 2;
console.log(x); // 2
}
console.log(x); // 2
let
- let
let x = 1;
console.log(x); // 1
if (true) {
console.log(x); // 1
x = 2;
console.log(x); // 2
}
console.log(x); // 2
let x = 1;
console.log(x); // 1
if (true) {
//console.log(x); // ReferenceError: x is not defined
let x = 2;
console.log(x); // 2
}
console.log(x); // 1
var let
var x = 1;
console.log(x); // 1
if (true) {
// console.log(x); // ReferenceError: x is not defined
let x = 2;
console.log(x); // 2
}
console.log(x); // 1
let var
let x = 1;
console.log(x); //
if (true) {
console.log(x); //
var x = 2; // SyntaxError: Identifier 'x' has already been declared
console.log(x); //
}
console.log(x); //
Create library
- require
function say_hi(name) {
console.log('Hello ' + name)
}
console.log('Loading module')
module.exports.say_hi = say_hi;
const lib = require('./lib')
console.log('Hello World')
lib.say_hi('Foo')
$ node examples/basic/app.js
Loading module
Hello World
Hello Foo
It is better to define as constant so we won't change it by mistake
Function as a Library
From a module we can export a module or a single function like this: // module.exports = hi;
function say_hi(name) {
console.log('Hello ' + name)
}
console.log('Loading module')
module.exports = say_hi;
const say_hi = require('./lib2')
console.log('Hello World')
say_hi('Foo')
$ node examples/basic/app2.js
Loading module
Hello World
Hello Foo
Loading a library twice
- Loads it only once but allows access to it from several names.
const say_hi = require('./lib2');
function other() {
const say_hello = require('./lib2');
say_hello('Bar');
}
console.log('Hello World');
say_hi('Foo');
other();
$ node examples/basic/app22.js
Loading module
Hello World
Hello Foo
Hello Bar
What is in a module?
-
module
-
The
module
object represents the current module -
See more about modules
console.log(module)
OS module
-
os
-
totalmem
-
freemem
-
uptime
-
loadavg
-
platform
-
hostname
-
type
-
tmpdir
-
networkInterfaces
-
A bunch of OS-related methods
const os = require('os')
console.log(os.totalmem())
console.log(os.freemem())
console.log(os.uptime())
console.log(os.loadavg())
console.log(os.platform())
console.log(os.hostname())
console.log(os.type())
console.log(os.tmpdir())
console.log(os.networkInterfaces())
The path related tools
Path to the current file
- __filename
- __dirname
console.log(__filename); // path to this file
console.log(__dirname); // path to the directory of this file
Relative path inside a project
- path
- dirname
- join
project_dir/
/bin/
code.js
/templates
main.html
const path = require('path');
console.log(__filename);
console.log(__dirname);
const root = path.dirname(__dirname)
console.log(root);
const templates = path.join(root, 'templates');
console.log(templates);
const rel_path_to_file = path.join(root, 'templates', 'main.html');
console.log(rel_path_to_file);
Exception
- throw
- Error
throw new Error("a problem, we have");
REPL
node
>
...
Ctrl-d
Debugging
Add "debugger;" to the code. That will set a breakpoint if running under the debugger. node debug code.js debug> help
debug> quit
- Node inspector
- Eclipse plugin
Callback
function call_back(cb) {
console.log("Start call_back");
cb();
//console.log("End call_back");
}
function helper() {
console.log("In helper function");
}
call_back(function() {
console.log("Inside anonymous function");
})
call_back(helper);
Closure
function createCounter(n) {
function counter(v) {
return v + n;
}
return counter;
}
var counter_3 = createCounter(3);
console.log(counter_3(7));
var counter_4 = createCounter(4);
console.log(counter_3(7));
console.log(counter_4(7));
File-system related operations (fs)
File-system related operations (fs)
- fs
- readFile
- writeFile
- appendFile
- unlink (delete file)
- createReadStream
- createWriteStream
- mkdir
- rmdir
- readdirSync
- readdir
- rename
Read file
- readFile
const fs = require('fs');
fs.readFile('data.txt', 'utf8', (err, content) => {
if (err) {
console.log(err);
} else {
console.log(content);
}
});
Write file
- writeFile
const fs = require('fs');
fs.writeFile('data.txt', 'first line', (err) => {
if (err) {
console.log(err);
} else {
console.log('Success');
}
});
Append to file
- appendFile
const fs = require('fs');
fs.appendFile('filename', 'content', (err) => {
if (err) {
console.log(err);
} else {
console.log('Success');
}
});
Delete file (unlink file)
- unlink
const fs = require('fs');
fs.unlink(filename, (err) => {
if (err) {
console.log(err);
} else {
console.log('Success');
}
});
Read (and write) file by chunks
- createReadStream
- createWriteStream
- on
- write
const fs = require('fs');
const readStream = fs.createReadStream('README', 'utf8'); // inherits from events
const writeStream = fs.createWriteStream('README.txt');
readStream.on('data', (chunk) => {
if (chunk) {
writeStream.write(chunk);
}
});
Read (and write) file by chunks using pipe
- pipe
const fs = require('fs');
const readStream = fs.createReadStream('README', 'utf8'); // inherits from events
const writeStream = fs.createWriteStream('README.txt');
readStream.pipe(writeStream);
Create a directory (folder) (mkdir)
- mkdir
const fs = require('fs');
fs.mkdir(dirname, (err) => {
if (err) {
console.log(err);
} else {
console.log('Success');
}
});
Remove a directory (folder) (rmdir)
- rmdir
const fs = require('fs');
fs.rmdir(dirname, (err) => {
if (err) {
console.log(err);
} else {
console.log('Success');
}
});
Read directory sync (readdirSync)
- readdirSync
const fs = require('fs')
let files = fs.readdirSync('.')
console.log(files)
Read directory async (readdir)
- readdir
const fs = require('fs')
fs.readdir('.', function (err, things) {
console.log(things)
});
Read directory async error handline
- readdir
const fs = require('fs')
fs.readdir('xyz', function (err, files) {
if (err) {
console.log('Error', err);
} else {
console.log(files);
}
})
Rename a file (rename)
- rename
fs.rename(from, to, (err) => {})
const fs = require('fs');
fs.rename('old.txt', 'new.txt', (err) => {
if (err) {
console.log(err);
} else {
console.log('Success');
}
});
OOP
Class
- new
- class
- constructor
class MyClass {
constructor() {
console.log('object created');
}
}
function f() {
const n = new MyClass();
console.log(n);
}
console.log('before');
f();
console.log('after');
HTTP
HTTP Hello World
- http
- createServer
- listen
const http = require('http'); // A subclass of the emitter
const server = http.createServer((req, res) => {
if (req.url === '/') {
res.write('Hello World');
res.end();
}
});
const port = 3000;
server.listen(port);
console.log(`Listening on port ${port}`);
HTTP Return JSON
- writeHead
- Content-type
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write('Hello World <a href="/api/users">users</a>');
res.end();
}
if (req.url === '/api/users') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write(JSON.stringify([1, 2, 3]));
res.end();
}
});
const port = 3000;
server.listen(port);
console.log(`Listening on port ${port}`);
HTTP Server
var http = require('http'); // Load the http library
var s = http.createServer(function(req, res) {
res.writeHeader(200, { 'Content-Type' : 'text/plain' });
res.end('Hello World\n');
});
s.listen(8000);
$ curl http://localhost:8000
Hello World
$ curl -i http://localhost:8000
HTTP/1.1 200 OK
content-type: text/plain
Date: Thu, 30 Jan 2014 21:03:36 GMT
Connection: keep-alive
Transfer-Encoding: chunked
Hello World
Point out the Connection: keep-alive - in modern web you can send several requsts on the same connection Transfer-Encoding: chunked - streaming
Transfer-Encoding: chunked
var http = require('http'); // Load the http library
var s = http.createServer(function(req, res) {
res.writeHeader(200, { 'Content-Type' : 'text/plain' });
res.write('Hello\n');
setTimeout(function() {
res.end('World\n');
}, 2000);
});
s.listen(8000);
In this example, if we fetch it with curl, we'll see the Hello arrives first and then after 2 seconds world arrives. This is what has been provided by the chunked parameter. This script might fetch some data from a database or from some other source. Instead of building up the whole response in the server and then sening it out only when it is ready, we send it out in chunks as parts of it got ready.
If there was a Content-Length the client could know when the data ends, but with chunked budy it has to use the http://en.wikipedia.org/wiki/Chunked_transfer_encoding which basically means, when a chunk of size 0 arrives that's the end of the current document.
Apache bench: ab -n 100 -c 100 http://127.0.0.1:8000/
Mashup
While one process is still "running" and printing "world" every 5 seconds, we add a new "process" fetching a website every 2 seconds. It just works.
setInterval(function() {
console.log("world");
}, 5000);
var http = require('http');
setInterval(function() {
console.log("fetching google.com");
http.get({ host: 'google.com' }, function(res) {
console.log(res.headers);
});
}, 2000);
console.log("hello");
Net
The net module
TCP Server
const net = require('net');
const server = net.createServer(function(socket) {
socket.write('hello\n');
socket.end('world\n');
});
server.listen(8000);
node examples/net/tcp-server.js
$ telnet localhost 8000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
world
Connection closed by foreign host.
TCP Echo Server
const net = require('net');
const server = net.createServer(function(socket) {
socket.write('hello\n');
socket.write('world\n');
socket.on('data', function(data) {
socket.write('You said: ' + data);
})
});
server.listen(8000);
Chat server
var net = require('net');
var sockets = [];
var s = net.Server(function(socket) {
sockets.push(socket);
socket.on('data', function(txt) {
for (var i=0; i < sockets.length; i++) {
sockets[i].write(txt);
}
});
});
s.listen(8000);
This works, but when someone disconnects, the dead socket remains in the array and when we try to write to it it will blow up.
Remove dead sockets
socket.on('end', function() {
var i = sockets.indexOf(socket);
sockets.splice(i, 1)
});
var net = require('net');
var sockets = [];
var s = net.Server(function(socket) {
sockets.push(socket);
socket.on('data', function(txt) {
for (var i=0; i < sockets.length; i++) {
sockets[i].write(txt);
}
});
socket.on('end', function() {
var i = sockets.indexOf(socket);
sockets.splice(i, 1)
});
});
s.listen(8000);
Stop echoing
if (sockets[i] == socket) continue;
const net = require('net');
var sockets = [];
const sock = net.Server(function(socket) {
sockets.push(socket);
socket.on('data', function(txt) {
for (var i = 0; i < sockets.length; i++) {
if (sockets[i] === socket) continue;
sockets[i].write(txt);
}
});
socket.on('end', function() {
var i = sockets.indexOf(socket);
sockets.splice(i, 1);
});
});
sock.listen(8000);
npm
npmjs
- npm
- Private npm repository in the cloud: https://gemfury.com/
npm init
- Create a directory for the project (eg. mynode) and cd into the directory
npm init
This will aske a few questions and create the package.json file.
The questions, and the default answers, you can just accept the defaults.
package name: mynode
version: 1.0.0
description:
entry point: index.js
test command:
git repository:
keywords:
author:
license (ISC):
npm init --yes
- Would populate the file with the defaults without asking emberassing questions.
package json
{% embed include file="src/examples/manual/package.json)
npm install PACKAGE
npm install module
npm uninstall module
- This will install in the
node_modules
folder in the directory where the package.json can be found - And it will add the name of the package to packege.json as well declaring it as a dependency
- It will also create a file called
package-lock.json
. - Both json files should be added to git and the node_modules/ directory should be added to gitignore
Development dependencies
npm install mocha --save-dev
- It is added to the
devDependencies
section in the package.json file
Semanic Versioning
^1.2.3 means 1.x.x
~1.2.3 means 1.2.x
1.2.3 exact version number
npm install
- Based on
pacakge.json
andpackage-lock.json
this will install all the depdendencies. - Useful to recreate the environment.
npm install
npx
Linter - ESLint
npm install eslint --save-dev
npx eslint --init
Creates:
.eslintrc.json
{% embed include file="src/examples/basic/.eslintrc.json)
- Set the rules
Run it:
npx eslint *.js
In package.json
set:
"scripts": {
"test": "npx eslint *.js"
},
Then run as
$ npm run test
Express
Install Express
npm install express
{% embed include file="src/examples/web-express/hello_world.js)
Testing for NodeJS projects
Testing - Application Under Test
function add(x, y) {
return x*y
}
function multiply(x, y) {
return x+y
}
module.exports ={
add, multiply
}
Using the JavaScript library
const {parseArgs} = require('node:util');
const calc = require("./mycalc.js");
const args = process.argv;
if (args.length != 4) {
console.log(`Usage ${args[1]} X Y`);
process.exit(1);
}
console.log(calc.add(args[2], args[3]));
node add.js
Testing Demo with Mocha
npm init -y npm install mocha npm install mocha-cli
{
"name": "testing-demo",
"version": "1.0.0",
"description": "",
"main": "add.js",
"scripts": {
"test": "mocha test"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"mocha": "^10.2.0",
"mocha-cli": "^1.0.1"
}
}
{
"name": "testing-demo",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
"integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA=="
},
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"requires": {
"color-convert": "^2.0.1"
}
},
"anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
}
},
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"requires": {
"fill-range": "^7.0.1"
}
},
"browser-stdout": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="
},
"camelcase": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"dependencies": {
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"requires": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"fsevents": "~2.3.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
}
},
"cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^7.0.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
},
"dependencies": {
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"decamelize": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
"integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ=="
},
"diff": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w=="
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
},
"escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"requires": {
"to-regex-range": "^5.0.1"
}
},
"find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"requires": {
"locate-path": "^6.0.0",
"path-exists": "^4.0.0"
}
},
"flat": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"optional": true
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"dependencies": {
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"requires": {
"brace-expansion": "^1.1.7"
}
}
}
},
"glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"requires": {
"is-glob": "^4.0.1"
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"requires": {
"function-bind": "^1.1.1"
}
},
"has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
"requires": {
"ansi-regex": "^2.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="
}
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"requires": {
"binary-extensions": "^2.0.0"
}
},
"is-core-module": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
"integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
"requires": {
"has": "^1.0.3"
}
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"requires": {
"is-extglob": "^2.1.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
"is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="
},
"is-unicode-supported": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="
},
"js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"requires": {
"argparse": "^2.0.1"
}
},
"locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"requires": {
"p-locate": "^5.0.0"
}
},
"log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
"integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
"requires": {
"chalk": "^4.1.0",
"is-unicode-supported": "^0.1.0"
}
},
"minimatch": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
"requires": {
"brace-expansion": "^2.0.1"
},
"dependencies": {
"brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"requires": {
"balanced-match": "^1.0.0"
}
}
}
},
"mocha": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
"integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
"requires": {
"ansi-colors": "4.1.1",
"browser-stdout": "1.3.1",
"chokidar": "3.5.3",
"debug": "4.3.4",
"diff": "5.0.0",
"escape-string-regexp": "4.0.0",
"find-up": "5.0.0",
"glob": "7.2.0",
"he": "1.2.0",
"js-yaml": "4.1.0",
"log-symbols": "4.1.0",
"minimatch": "5.0.1",
"ms": "2.1.3",
"nanoid": "3.3.3",
"serialize-javascript": "6.0.0",
"strip-json-comments": "3.1.1",
"supports-color": "8.1.1",
"workerpool": "6.2.1",
"yargs": "16.2.0",
"yargs-parser": "20.2.4",
"yargs-unparser": "2.0.0"
}
},
"mocha-cli": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mocha-cli/-/mocha-cli-1.0.1.tgz",
"integrity": "sha512-cRBJVwtw1+ZE7+J0lvSaR+c0tE7rLX9Slca6f/6f6eq8L0TdcPminauCconsvPiAENbt0qkpleTd2AUCD8nFzg==",
"requires": {
"chalk": "^1.1.1",
"debug": "^2.2.0",
"resolve": "^1.1.7"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA=="
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
"requires": {
"ansi-regex": "^2.0.0"
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g=="
}
}
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"nanoid": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
"integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w=="
},
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"requires": {
"wrappy": "1"
}
},
"p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"requires": {
"yocto-queue": "^0.1.0"
}
},
"p-locate": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"requires": {
"p-limit": "^3.0.2"
}
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
},
"path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"requires": {
"safe-buffer": "^5.1.0"
}
},
"readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"requires": {
"picomatch": "^2.2.1"
}
},
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
},
"resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
"requires": {
"is-core-module": "^2.9.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
"integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
"requires": {
"randombytes": "^2.1.0"
}
},
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
}
},
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"requires": {
"ansi-regex": "^5.0.1"
}
},
"strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
},
"supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"requires": {
"has-flag": "^4.0.0"
}
},
"supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"requires": {
"is-number": "^7.0.0"
}
},
"workerpool": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
"integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw=="
},
"wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
},
"yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"requires": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
}
},
"yargs-parser": {
"version": "20.2.4",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
"integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA=="
},
"yargs-unparser": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
"integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
"requires": {
"camelcase": "^6.0.0",
"decamelize": "^4.0.0",
"flat": "^5.0.2",
"is-plain-obj": "^2.1.0"
}
},
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
}
}
}
Testing Demo with Mocha success
var assert = require('assert');
const calc = require("../mycalc.js")
describe('Array', function() {
describe('calc', function() {
it('should be ok', function() {
assert.equal(calc.add(2, 2), 4);
});
});
});
./node_modules/mocha/bin/mocha.js test/first.js
Testing Demo with Mocha failure
var assert = require('assert');
const calc = require("../mycalc.js")
describe('Array', function() {
describe('calc', function() {
it('should be ok', function() {
assert.equal(calc.add(2, 2), 4);
});
it('should be ok', function() {
assert.equal(calc.add(2, 3), 5);
});
});
});
./node_modules/mocha/bin/mocha.js test/several.js
Appendix
Other
Because node.js does not live in the browser it does not have the DOM. But it has a main object called process
and you can ask for process.pid
.
Node exits when it has nothing more to do. It reference counts the callbacks and when that goes to 0 it exits.
We can use global.console.log() or console.log()
A TAP test framework for Node.js
Resources
- Ryan Dahl (author of node.js)
- [How do I get started with Node.JS](https://stackoverflow.com/questions/2353818/how-do-i-get-started-with-node.js" %}
- Node.js Tutorial for Beginners: Learn Node in 1 Hour | Mosh
- Learn Node.js - Full Tutorial for Beginners
- The Node Beginner Book
request
npm install request
node http_request.js
const request = require('request');
//let url = 'http://httpbin.org/get'
let url = 'https://httpbin.org/get'
let options = {
url: url,
headers: {
'User-Agent': 'My Awesone Node browser'
}
};
request(options, function (error, response, body) {
if (error) {
console.log('Something went wrong ', error)
} else {
console.log("Status code: " + response.statusCode);
console.log(response.body);
}
});
http client
const http = require('http');
url = 'http://httpbin.org/get';
http.get(url, (res) => {
const { statusCode } = res;
console.error("StatusCode " + statusCode);
if (statusCode !== 200) {
console.log("Error");
// Consume response data to free up memory
res.resume();
return;
}
let rawData = '';
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
console.log(rawData);
});
});
node http_agent.js
ping
const ping = require("net-ping");
let host = "8.8.8.8";
const session = ping.createSession();
session.pingHost(host, function(error, target) {
if (error)
console.log(target + ": " + error.toString());
else
console.log(target + ": Alive");
});
npm install net-ping
sudo /opt/node/bin/node ping_demo.js
Telnet server
const telnet = require('telnet');
telnet.createServer(function(client) {
// client.on("error", function(err) {
// //console.log(err.stack);
// console.log(
// });
client.write('My banner');
client.do.window_size();
}).listen(8080);
HTTP Server
const http = require('http')
http.createServer(function(req, res) {
res.writeHead(200, 'Header');
res.write('Reply\n');
let html = '<html><head><title>Title</title></head><body></body></html>';
res.write(html);
res.set
res.end();
}).listen(8080);