2

I don't understand how Chalk's (NodeJS module) syntax works (and it bothers me). I have searched far and wide for an answer, but I am not having any luck and likely don't know the technical term(s) for what I need to look for. I have tried looking up chalk-specific questions here on StackOverflow, "method chaining", "prototypes", etc. Tried looking at Chalk's source code, but still can't seem to figure out my answer. The syntax in question is:

// Code snippet from the Chalk NPM Page.
log(chalk.blue.bgRed.bold('Hello world!'));
log(chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz'));

I am familiar with method chaining and familiar with storing a function in an object. The main question I have is: how can chalk.blue be a property and a function at the same time?

Any help would be greatly appreciated. Whether it is a full explanation or a push in the right direction.

Trevor
  • 37
  • 6
  • Simple. The object `blue` contains a property `bgRed`. Give me a sec to write a demo in an answer – slebetman Jul 15 '21 at 04:23
  • While I was writing an answer I realised what the real answer is: getters and setters: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get – slebetman Jul 15 '21 at 04:31
  • In Javascript, functions are objects and can have properties. So if `chalk.blue` is a function, it can also have properties like `chalk.blue.bgRed`. – jfriend00 Jul 15 '21 at 04:41

2 Answers2

5

Chalk is probably using getters and setters to "call" the appropriate functions. The following is a simple example of what's going on:

let a = function (txt) {
    console.log(a.buffer + txt);
    a.buffer = ''
}

a.buffer = '';

Object.defineProperty(a,'b',{
    get: function(){
        this.buffer += '<B>';
        return this
    }
});

Object.defineProperty(a,'c',{
    get: function(){
        this.buffer += '<C>';
        return this
    }
});

Object.defineProperty(a,'d',{
    get: function(){
        this.buffer += '<D>';
        return this
    }
});

Basically it's just regular method chaining but using getters to make it fancy! Another trick is to make the base object a Function instead of a regular object so that the this you return becomes callable.

Now you can do:

a.b.c.b.d('hello'); // prints <B><C><B><D>hello
slebetman
  • 109,858
  • 19
  • 140
  • 171
2

The main question I have is: how can chalk.blue be a property and a function at the same time?

In Javascript, a function is an object so in addition to be callable as chalk.blue(), it can also have properties such as chalk.blue.bgRed.

For example, you can do this:

function callMe() {
    console.log("callMe");    
}

callMe.greeting = "hello";

callMe();
console.log(callMe.greeting);

Then, for indefinite chaining, you can use getters to create endless chains of objects.

jfriend00
  • 683,504
  • 96
  • 985
  • 979