2

So, I'm doing a nodejs tutorial, but the tutorial isn't updated to ES6 and I just wanted to update the code as I go along. I get the program to run just fine using require('yargs'), but keep getting yargs.command, yargs.argv, etc. is not a function. It's my understanding that nodejs now supports import/export statements, as does yargs. I have set my app as "type: module" and saved as an .mjs file. Listed below is the working vs. non-working(ES6) with terminal output. If anyone can spot my error please let me know...

Working code...

// ipmort module libraries from node package manager
const yargs = require('yargs')
const notes = require('./notes.js')

// Output colors
const chalk = require('chalk')
let jenkinsColor = '#bd93f9'
let successColor = '#50fa7b'
let failureColor = '#ff5555'

// Yargs stored version number
yargs.version('1.0.0')

// --- ADD COMMAND ----
yargs.command({
  command: 'add',
  describe: 'Have Jenkins add a new note',
  builder: {
    title: {
      describe: 'Note title',
      demandOption: true,
      type: 'string'
    },
    body: {
      describe: 'Note content',
      demandOption: true,
      type: 'string'
    }
  },
  handler(argv) {
    notes.addNote(argv.title, argv.body)
  }
})

// --- REMOVE COMMAND ----
yargs.command({
  command: 'remove',
  describe: 'Have Jenkins remove an existing note',
  builder: {
    title: {
      describe: 'Note to be deleted',
      demandOption: true,
      type: 'string'
    }
  },
  handler(argv) {
    notes.removeNote(argv.title)
  } 
})

// --- READ COMMAND ----
yargs.command({
  command: 'read',
  describe: 'Have Jenkins read your notes',
  handler() {
    console.log('Reading your notes, sir...')
  }
})

// --- LIST COMMAND ----
yargs.command({
  command: 'list',
  describe: 'Have Jenkins list your notes',
  handler() {
   console.log('Removing your note, sir...')
  }
})

yargs.parse()

Terminal...

node-notes-app$ node app.js add --title="Test Title" --body="testing testing 123"

      ...............................
      + Test Title
      ...............................
      + + testing testing 123
    
SUCCESS
Adding your new note to your list, sir...
christopher@rra-debian-desktop:~/Documents/IBM/FED/NodeJS/node-notes-app$ 

ES6

// import module libraries from node package manager
import yargs from 'yargs'
// import notes from './notes.js'

// Yargs stored version number
yargs.version('1.0.0')

// --- ADD COMMAND ----
yargs.command({
  command: 'add',
  describe: 'Have Jenkins add a new note',
  builder: {
    title: {
      describe: 'Note title',
      demandOption: true,
      type: 'string'
    },
    body: {
      describe: 'Note content',
      demandOption: true,
      type: 'string'
    }
  },
  handler(argv) {
    notes.addNote(argv.title, argv.body)
  }
})

// --- REMOVE COMMAND ----
yargs.command({
  command: 'remove',
  describe: 'Have Jenkins remove an existing note',
  builder: {
    title: {
      describe: 'Note to be deleted',
      demandOption: true,
      type: 'string'
    }
  },
  handler(argv) {
    notes.removeNote(argv.title)
  } 
})

// --- READ COMMAND ----
yargs.command({
  command: 'read',
  describe: 'Have Jenkins read your notes',
  handler() {
    console.log('Reading your notes, sir...')
  }
})

// --- LIST COMMAND ----
yargs.command({
  command: 'list',
  describe: 'Have Jenkins list your notes',
  handler() {
   console.log('Removing your note, sir...')
  }
})

yargs.parse()

Terminal....

app.mjs:12
yargs.version('1.0.0')
      ^

TypeError: yargs.version is not a function
    at file:///home/christopher/Documents/IBM/FED/NodeJS/node-notes-app/app.mjs:12:7
    at ModuleJob.run (internal/modules/esm/module_job.js:152:23)
    at async Loader.import (internal/modules/esm/loader.js:166:24)
    at async Object.loadESM (internal/process/esm_loader.js:68:5)
Ctcoleman
  • 71
  • 7

1 Answers1

4

I posted this issue on github...here is the solution (https://github.com/yargs/yargs/issues/1854).

This is explained in the Advanced Topics README.file (https://github.com/yargs/yargs/blob/master/docs/advanced.md)

Example command hierarchy using index.mjs

To support creating a complex nested CLI when using ESM, the method .command() was extended to accept an array of command modules. Rather than using .commandDir(), create an index.mjs in each command directory with a list of the commands:

cmds/index.mjs:

import * as a from './init.mjs'; import * as b from './remote.mjs';
export const commands = [a, b];

This index will then be imported and registered with your CLI:

cli.js:

#!/usr/bin/env node

import yargs from 'yargs'; import { hideBin } from 'yargs/helpers';
import { commands } from './cmds/index.mjs';
 
yargs(hideBin(process.argv))
  .command(commands)
  .argv;

Here is a partial of my reformatted working code app.mjs

// import module libraries from node package manager
import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'
import notes from './notes.mjs'

const yarg = yargs(hideBin(process.argv))

// Yargs stored version number
yarg.version('1.0.0')

// --- ADD COMMAND ----
yarg.command({
  command: 'add',
  describe: 'Have Jenkins add a new note',
  builder: {
    title: {
      describe: 'Note title',
      demandOption: true,
      type: 'string'
    },
    body: {
      describe: 'Note content',
      demandOption: true,
      type: 'string'
    }
  },
  handler(argv) {
    notes.addNote(argv.title, argv.body)
  }
})

And the terminal output...

~/Projects/IBM/BED/NodeJS/node-notes-app$ node app.mjs --help
app.mjs [command]

Commands:
  app.mjs add     Have Jenkins add a new note
  app.mjs remove  Have Jenkins remove an existing note
  app.mjs read    Have Jenkins read your notes
  app.mjs list    Have Jenkins list your notes

Options:
  --help     Show help                                                 [boolean]
  --version  Show version number                                       [boolean]
Ctcoleman
  • 71
  • 7
  • This is working, I'm not sure why it's downvoted. With ES6 module imports, we need to instantiate Yargs like this `const yarg = yargs(hideBin(process.argv))` before we use the class instance methods like `yargs.terminalWidth()`. – Christos Lytras Nov 18 '21 at 12:01
  • it's the only useful answer i got in the net for this problem , thank you @ChristosLytras – sohaieb azaiez Dec 18 '21 at 10:39