The introduction of the library
A tiny JavaScript debugging tool modeled on the core debugging technology of Node.js. Works with Node.js and Web browser portals
knowledge
Determine whether the node or browser environment is broken.
src/index.js
if (typeof process === 'undefined' || process.type === 'renderer' || process.browser === true || process.__nwjs) {
module.exports = require('./browser.js');
} else {
module.exports = require('./node.js');
}
Copy the code
- Process. type === ‘renderer’ checks whether the electron environment is generated.
- Webpack defines process.browser to return true in browser, false in Node (Webpack determines browser corruption based on document).
- Process. __nwjs determines whether it is an NWJS environment. (similar to electron) official portal
Check whether the terminal supports colors
Use the supports color library to determine whether the terminal supports colors.
src/node.js
exports.colors = [ 6.2.3.4.5.1 ];
try {
var supportsColor = require('supports-color');
if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) {
exports.colors = [
20.21.26.27.32.33.38.39.40.41.42.43.44.45.56.57.62.63.68.69.74.75.76.77.78.79.80.81.92.93.98.99.112.113.128.129.134.135.148.149.160.161.162.163.164.165.166.167.168.169.170.171.172.173.178.179.184.185.196.197.198.199.200.201.202.203.204.205.206.207.208.209.214.215.220.221]; }}catch (err) {
// swallow - we only care if `supports-color` is available; it doesn't have to be.
}
Copy the code
Pass the parameter as an environment variable
Debug allows the user to define options in the following format (equivalent to passing arguments to a program)
$ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js
Copy the code
Cooler than node Script –xx=xx, the usual format for passing arguments to programs.
exports.inspectOpts = Object.keys(process.env).filter(function (key) {
return /^debug_/i.test(key);
}).reduce(function (obj, key) {
var prop = key
.substring(6)
.toLowerCase()
.replace(/_([a-z])/g.function (_, k) { return k.toUpperCase() });
var val = process.env[key];
if (/^(yes|on|true|enabled)$/i.test(val)) val = true;
else if (/^(no|off|false|disabled)$/i.test(val)) val = false;
else if (val === 'null') val = null;
else val = Number(val);
obj[prop] = val;
return obj;
}, {});
Copy the code
Parameters set in the above format are stored in process.env. Env is an object. For example, DEBUG_COLORS=no, where DEBUG_COLORS is the key and no is value.
Such as:
DEBUG_COLORS=no DEBUG_DEPTH=10
process.env = {
DEBUG_COLORS: no,
DEBUG_DEPTH: 10
}
Copy the code
Use reduce to convert arrays to objects
To convert an array to an object by reduce, the trick is to initialize the second (optional) reduce argument.
var list = [1.2.3.4];
var a = list.reduce((obj,num) = >{
// obj is initialized for the first time {}
obj[`${num}`] = num;
returnobj; }, {})console.log(a);
//a : { '1': 1, '2': 2, '3': 3, '4': 4 }
Copy the code
Regex handles multi-value decisions
if (/^(yes|on|true|enabled)$/i.test(val)) val = true;
else if (/^(no|off|false|disabled)$/i.test(val)) val = false;
else if (val === 'null') val = null;
else val = Number(val);
Copy the code
Processing strings with the same meaning through regex is much more elegant than using ===.
//bad
if(val === 'yes' || val === 'on' || val === 'true'){
val = true;
}
//good
if (/^(yes|on|true|enabled)$/i.test(val)) val = true;
Copy the code
Common logic extraction
SRC /common.js is a public module and the exported value is createDebug. Both Node and browser scenarios are eventually passed into Common as parameters, which separates code and groups reusable code together.
An assignment between two objects
If env is an environment object, mount all of env’s properties to createDebug. This allows the env object to be extended at will, and eventually all methods are assigned to the exported object createDebug.
src/common.js
// Assign operation source code
Object.keys(env).forEach(function(key) {
createDebug[key] = env[key];
});
// A quick way to write
let obj1 = {'name':'cxr'.'age':18};
letobj2 = {... obj1};console.log(obj2);//{ name: 'cxr', age: 18 }
console.log(obj1 === obj2);//false
Copy the code
Check whether the Node running environment is terminal
With the TTY module (the nodeJS native module), when Node.js detects that it is running on a text terminal (TTY), process.stdin is initialized as an instance of tty.ReadStream by default, And process.stdout and process.stderr are initialized as tty.WriteStream instances by default. Check by isTTY: Return true if it is an instance of tty.WriteStream.
// writestream.istty always returns true
if(process.stdout.isTTY === true)
Copy the code
File descriptor (FD)
The first thing to understand is that under Linux, everything is a file. The kernel accesses files using file descriptors. The file descriptor is a non-negative integer. When an existing file is opened or a new file is created, the kernel returns a file descriptor. Reading and writing files also requires a file descriptor to specify the file to be read or written to. Linux under:
- 0 is the file descriptor for standard input -> stdin.
- 1 is the file descriptor for standard output -> stdout.
- 2 is the file descriptor for standard error output -> stderr.
Describe the portal in detail
Here process.stderr.fd returns a fd as an argument, and tty. Isatty checks true if the given FD is associated with a TTY, and false otherwise. In other words, whether the output stream is in the terminal.
// The user will check if the error stream is in the terminal without setting the color option
function useColors() {
return 'colors' in exports.inspectOpts
? Boolean(exports.inspectOpts.colors)
: tty.isatty(process.stderr.fd);
}
Copy the code
ANSI escape codes
Used to control cursor position, color and other options on the video text terminal. Certain sequences of bytes (most beginning with Esc and ‘[‘) are embedded in the text, which the terminal looks up and interprets as commands rather than character codes
Node writing format:
\u001b[31mHello It will be parsed to output red Hello.Copy the code
Change terminal font color in Node:
//31m is red and 32m is green
console.log('\u001b[31mHello \u001b[32mWorld');
Copy the code
Customize the formatting function
Debug allows users to customize formatting plug-ins, for example:
const createDebug = require('debug')
createDebug.formatters.h = (v) => {
return v.toString('hex'} / /... elsewhere const debug = createDebug('foo')
debug('this is hex: %h', new Buffer('hello world'))
// foo this is hex: 68656c6c6f20776f726c6421 +0ms
Copy the code
You can see that you only need to mount the custom function H on the CreateDebug.Formatters object. The user – defined function is called when %h is found when formatting the output. Source code implementation:
// apply any `formatters` transformations
var index = 0;
args[0] = args[0].replace(/%([a-zA-Z%])/g.function(match, format) {
// if we encounter an escaped % then don't increase the array index
if (match === '% %') return match;
index++;
var formatter = createDebug.formatters[format];
if ('function'= = =typeof formatter) {
var val = args[index];
match = formatter.call(self, val);
// now we need to remove `args[index]` since it's inlined in the `format`
args.splice(index, 1);
index--;
}
return match;
});
// apply env-specific formatting (colors, etc.)
createDebug.formatArgs.call(self, args);
Copy the code
- Take the character after %
- Calls the function defined on CreateDebug.Formatters based on a character match
- Based on the return value of the function, replace
It follows the closed to modification, open to extension principle (OCP).
conclusion
Finally, the learned knowledge is summarized as follows:
- Node and browser environment differentiation.
- Duplicate code extraction –DRY
- Closed for modifications, open for extensions –OCP
- ANSI escape codes
- Pass the parameter as an environment variable
Through reading excellent source code to improve their own, thick accumulation. Welcome to correct ~