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
  1. Take the character after %
  2. Calls the function defined on CreateDebug.Formatters based on a character match
  3. 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:

  1. Node and browser environment differentiation.
  2. Duplicate code extraction –DRY
  3. Closed for modifications, open for extensions –OCP
  4. ANSI escape codes
  5. Pass the parameter as an environment variable

Through reading excellent source code to improve their own, thick accumulation. Welcome to correct ~