9f8daecd9e466c8387b36af742d2b47a6c941ef6.svn-base 24.9 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825
const { jack, num, opt, list, flag, env } = require('jackspeak')

const {cpus} = require('os')
const colorSupport = require('color-support')

const reporters = [...new Set([
  ...(require('tap-mocha-reporter').types),
  ...(require('treport/types')),
])]
const fs = require('fs')
// nyc bundles its deps, pull reporters out of it
const nycReporters = [
  'clover',
  'cobertura',
  'html',
  'json',
  'json-summary',
  'lcov',
  'lcovonly',
  'none',
  'teamcity',
  'text',
  'text-lcov',
  'text-summary',
]

const pkg = require('../package.json')

module.exports = main => jack({
  main,
  usage: 'tap [options] [<files>]',
  help:`
${pkg.name} v${pkg.version} - ${pkg.description}

Executes all the files and interprets their output as TAP
formatted test result data.  If no files are specified, then
tap will search for testy-looking files, and run those.
(See '--test-regex' below.)

To parse TAP data from stdin, specify "-" as a filename.

Short options are parsed gnu-style, so for example '-bCRspec' would be
equivalent to '--bail --no-color --reporter=spec'

If the --check-coverage or --coverage-report options are provided
explicitly, and no test files are specified, then a coverage report or
coverage check will be run on the data from the last test run.

Coverage is never enabled for stdin.

Much more documentation available at: https://www.node-tap.org/
`,

}, {
  description: 'Basic Options',

  reporter: opt({
    hint: 'type',
    short: 'R',
    default: null,
    description: `Use the specified reporter.  Defaults to
                  'base' when colors are in use, or 'tap'
                  when colors are disabled.

                  In addition to the built-in reporters provided by
                  the treport and tap-mocha-reporter modules, the
                  reporter option can also specify a command-line
                  program or a module to load via require().

                  Command-line programs receive the raw TAP output
                  on their stdin.

                  Modules loaded via require() must export either a
                  writable stream class or a React.Component subclass.
                  Writable streams are instantiated and piped into.
                  React components are rendered using Ink, with tap={tap}
                  as their only property.

                  Available built-in reporters:
                  ${reporters.join(' ')}`,
  }),

  'reporter-arg': list({
    hint: 'arg',
    short: 'r',
    description: `Args to pass to command-line reporters.  Ignored when using
                  built-in reporters or module reporters.`,
  }),

  'save-fixture': flag({
    short: 'F',
    envDefault: 'TAP_SAVE_FIXTURE',
    description: 'Do not clean up fixtures created with t.testdir()',
  }),

  bail: flag({
    short: 'b',
    envDefault: 'TAP_BAIL',
    description: 'Bail out on first failure',
    negate: {
      short: 'B',
      description: 'Do not bail out on first failure (default)'
    }
  }),

  comments: flag({
    description: 'Print all tap comments to process.stderr'
  }),

  color: flag({
    short: 'c',
    envDefault: 'TAP_COLORS',
    default: process.stdout.isTTY,
    description: 'Use colors (Default for TTY)',
    negate: {
      short: 'C',
      description: 'Do not use colors (Default for non-TTY)'
    }
  }),

  snapshot: flag({
    short: 'S',
    envDefault: 'TAP_SNAPSHOT',
    default: /^snap(shot)?$/.test('' + process.env.npm_lifecycle_event),
    description: `Set to generate snapshot files for
                  't.matchSnapshot()' assertions.`,
  }),

  watch: flag({
    short: 'w',
    description: `Watch for changes in the test suite or covered program.

                  Runs the suite normally one time, and from then on,
                  re-run just the portions of the suite that are required
                  whenever a file changes.

                  Opens a REPL to trigger tests and perform various actions.`,
  }),

  changed: flag({
    short: 'n',
    description: `Only run tests for files that have changed since the last
                  run.

                  This requires coverage to be enabled, because tap uses
                  NYC's process info tracking to monitor which file is loaded
                  by which tests.

                  If no prior test run data exists, then all default files are
                  run, as if --changed was not specified.`,
  }),
  'only-changed': flag({
    alias: '--changed',
    hidden: true,
  }),
  'onlyChanged': flag({
    alias: '--changed',
    hidden: true,
  }),

  save: opt({
    short: 's',
    hint: 'file',
    default: null,
    description: `If <file> exists, then it should be a line-
                  delimited list of test files to run.  If
                  <file> is not present, then all command-line
                  positional arguments are run.

                  After the set of test files are run, any
                  failed test files are written back to the
                  save file.

                  This way, repeated runs with -s<file> will
                  re-run failures until all the failures are
                  passing, and then once again run all tests.

                  Its a good idea to .gitignore the file
                  used for this purpose, as it will churn a
                  lot.`,
  }),

  only: flag({
    short: 'O',
    envDefault: 'TAP_ONLY',
    description: `Only run tests with {only: true} option,
                  or created with t.only(...) function.`,
  }),

  grep: list({
    hint: 'pattern',
    short: 'g',
    envDefault: 'TAP_GREP',
    delimiter: '\n',
    description: `Only run subtests tests matching the specified
                  pattern.

                  Patterns are matched against top-level
                  subtests in each file.  To filter tests
                  at subsequent levels, specify this
                  option multiple times.

                  To specify regular expression flags,
                  format pattern like a JavaScript RegExp
                  literal.  For example: '/xyz/i' for
                  case-insensitive matching.`,
  }),
  invert: flag({
    envDefault: 'TAP_GREP_INVERT',
    default: false,
    short: 'i',
    description: 'Invert the matches to --grep patterns. (Like grep -v)',
    negate: { short: 'I' }
  }),

  timeout: num({
    min: 0,
    short: 't',
    hint: 'n',
    envDefault: 'TAP_TIMEOUT',
    default: 30,
    description: `Time out test files after <n> seconds.
                  Defaults to 30, or the value of the
                  TAP_TIMEOUT environment variable.
                  Setting to 0 allows tests to run
                  forever.

                  When a test process calls t.setTimeout(n) on the top-level
                  tap object, it also updates this value for that specific
                  process.`,
  }),

  'no-timeout': flag({
    short: 'T',
    alias: '--timeout=0',
    description: 'Do not time out tests. Equivalent to --timeout=0.',
  }),

  files: list({
    description: `Alternative way to specify test set rather than using
                  positional arguments.  Supported as an option so that
                  test file arguments can be specified in .taprc and
                  package.json files.`
  }),

}, {

  description: 'Running Parallel Tests',

  help: `Tap can run multiple test files in parallel.  This generally
         results in a speedier test run, but can also cause problems if
         your test files are not designed to be independent from one
         another.

         To designate a set of files as ok to run in parallel, add them
         to a folder containing a file named 'tap-parallel-ok'.

         To designate a set of files as not ok to run in parallel, add
         them to a folder containing a file named 'tap-parallel-not-ok'.

         These folders may be nested within one another, and tap will
         do the right thing.`,

  jobs: num({
    short: 'j',
    hint: 'n',
    min: 1,
    default: Math.min(cpus().length, 8),
    description: `Run up to <n> test files in parallel.

                  By default, this will be set to the number of CPUs on
                  the system.

                  Set --jobs=1 to disable parallelization entirely.`
  }),

  'jobs-auto': flag({
    short: 'J',
    alias: '--jobs=' + cpus().length,
    description: `Run test files in parallel (auto calculated)

                  This is the default as of v13, so this option serves
                  little purpose except to re-set the parallelization
                  back to the default if an earlier option (or config file)
                  set it differently.
                  `
  }),

  before: opt({
    hint: 'module',
    description: `A node program to be run before test files are executed.

                  Exiting with a non-zero status code or a signal will fail
                  the test run and exit the process in error.`,
  }),
  after: opt({
    hint: 'module',
    description: `A node program to be executed after tests are finished.

                  This will be run even if a test in the series fails with
                  a bailout, but it will *not* be run if a --before script
                  fails.

                  Exiting with a non-zero status code or a signal will fail
                  the test run and exit the process in error.`,
  }),

}, {

  description: 'Code Coverage Options',

  help: `Tap uses the nyc module internally to provide code coverage, so
         there is no need to invoke nyc yourself or depend on it
         directly unless you want to use it in other scenarios.`,

  '100': flag({
    alias: [
      '--branches=100',
      '--lines=100',
      '--functions=100',
      '--statements=100'
    ],
    description: `Enforce full coverage, 100%.
                  Sets branches, statements, functions,
                  and lines to 100.

                  This is the default.  To specify a lower limit
                  (or no limit) set --lines, --branches, --functions,
                  or --statements to a lower number than 100, or disable
                  coverage checking with --no-check-coverage, or disable
                  coverage entirely with --no-coverage.`,
  }),

  'coverage-map': opt({
    short: 'M',
    hint: 'module',
    description: `Provide a path to a node module that exports a single
                  function.  That function takes a test file as an argument,
                  and returns an array of files to instrument with coverage
                  when that file is run.

                  This is useful in cases where a unit test should cover
                  a single portion of the system under test.

                  Return 'null' to not cover any files by this test.

                  Return an empty array [] to cover the set that nyc would
                  pull in by default.  Ie, returning [] is equivalent to not
                  using a coverage map at all.`,
  }),

  'no-coverage-map': flag({
    description: `Do not use a coverage map.
                  Primarily useful for disabling a coverage-map that is
                  set in a config file.`,
  }),

  coverage: flag({
    default: true,
    short: 'cov',
    description: `Capture coverage information using 'nyc'
                  This is enabled by default.

                  If a COVERALLS_REPO_TOKEN environment
                  variable is set, then coverage is
                  sent to the coveralls.io service.`,
    negate: {
      short: 'no-cov',
      description: `Do not capture coverage information.
                    Note that if nyc is already loaded, then
                    the coverage info will still be captured.`,
    }
  }),

  'coverage-report': list({
    hint: 'type',
    valid: nycReporters,
    description: `Output coverage information using the
                  specified istanbul/nyc reporter type.

                  Default is 'text' when running on the
                  command line, or 'text-lcov' when piping
                  to coveralls.

                  If 'html' is used, then the report will
                  be opened in a web browser after running.

                  This can be run on its own at any time
                  after a test run that included coverage.

                  Available NYC reporters:
                  ${nycReporters.join(' ')}`,
  }),

  'no-coverage-report': flag({
    description: `Do not output a coverage report, even if coverage
                  information is generated.`
  }),

  browser: flag({
    description: `Open a browser when an html coverage report is generated.
                  (this is the default behavior)`,
    default: true,
    negate:  {
      description: `Do not open a web browser after generating
                    an html coverage report`,
    }
  }),

  'show-process-tree': flag({
    description: `Enable coverage and display the tree of
                  spawned processes.`,
    implies: {
      coverage: true
    },
    short: 'pstree',
  }),

}, {
  description: 'Coverage Enfocement Options',
  help: `
    These options enable you to specify that the test will fail
    if a given coverage level is not met.  Setting any of the options
    below will trigger the --coverage and --check-coverage flags.

    The most stringent is --100.  You can find a list of projects
    running their tests like this at: https://www.node-tap.org/100

    If you run tests in this way, please add your project to the list.`,

  'check-coverage': flag({
    description: `Check whether coverage is within
                  thresholds provided.  Setting this
                  explicitly will default --coverage to
                  true.

                  This can be run on its own any time
                  after a test run that included coverage.`,
    implies: {
      coverage: true
    },
  }),

  branches: num({
    min: 0,
    max:100,
    default: 100,
    hint: 'n',
    implies: {
      'check-coverage': true,
      coverage: true
    },
    description: `what % of branches must be covered?`,
  }),

  functions: num({
    min: 0,
    max:100,
    default: 100,
    hint: 'n',
    implies: {
      'check-coverage': true,
      coverage: true
    },
    description: `what % of functions must be covered?`,
  }),

  lines: num({
    min: 0,
    max:100,
    default: 100,
    hint: 'n',
    implies: {
      'check-coverage': true,
      coverage: true
    },
    description: `what % of lines must be covered?`,
  }),

  statements: num({
    min: 0,
    max:100,
    default: 100,
    hint: 'n',
    implies: {
      'check-coverage': true,
      coverage: true
    },
    description: `what % of statements must be covered?`,
  }),

}, {
  description: 'Other Options',

  help: flag({
    short: 'h',
    description: 'Show this helpful output'
  }),

  version: flag({
    short: 'v',
    description: 'Show the version of this program.',
  }),

  'test-regex': opt({
    hint: 'pattern',
    // anything in a test/ or tests/ folder, or a /tests.js or /test.js,
    // or anything ending in *.test.js or *.spec.js
    default: '((\\/|^)(tests?|__tests?__)\\/.*|\\.(tests?|spec)|^\\/?tests?)\\.([mc]js|[jt]sx?)$',
    description: `A regular expression pattern indicating tests to run if no
                  positional arguments are provided.

                  By default, tap will search for all files ending in
                  .ts, .tsx, .js, .jsx, .cjs, or .mjs, in a top-level folder
                  named test, tests, or __tests__, or any file ending in
                  '.spec.' or '.test.' before a supported extension, or a
                  top-level file named 'test.(js,jsx,...)' or
                  'tests.(js,jsx,...)'

                  Ie, the default value for this option is:
                  ((\\/|^)(tests?|__tests?__)\\/.*|\\.(tests?|spec)|^\\/?tests?)\\.([mc]js|[jt]sx?)$
                  `
  }),

  'test-ignore': opt({
    hint: 'pattern',
    default: '$.',
    description: `When no positional arguments are provided, use the supplied
                  regular expression pattern to exclude tests that would
                  otherwise be matched by the test-regexp.

                  Defaults to '$.', which intentionally matches nothing.

                  Note: folders named tap-snapshots, node_modules, .git, and
                  .hg are ALWAYS excluded from the default test file set.  If
                  you wish to run tests in these folders, then name the test
                  files on the command line as positional arguments.`,
  }),

  'test-arg': list({
    hint: 'arg',
    description: `Pass an argument to test files spawned
                  by the tap command line executable.
                  This can be specified multiple times to
                  pass multiple args to test scripts.`,
  }),

  'test-env': list({
    hint: 'key[=<value>]',
    description: `Pass a key=value (ie, --test-env=key=value) to set an
                  environment variable in the process where tests are run.

                  If a value is not provided, then the key is ensured to
                  not be set in the environment.  To set a key to the empty
                  string, use --test-env=key=`,
  }),

  'nyc-arg': list({
    hint: 'arg',
    description: `Pass an argument to nyc when running
                  child processes with coverage enabled.
                  This can be specified multiple times to
                  pass multiple args to nyc.`,
  }),

  'node-arg': list({
    hint: 'arg',
    description: `Pass an argument to Node binary in all
                  child processes.  Run 'node --help' to
                  see a list of all relevant arguments.
                  This can be specified multiple times to
                  pass multiple args to Node.`,
  }),
  'expose-gc': flag({
    short: 'gc',
    alias: '--node-arg=--expose-gc',
    description: 'Expose the gc() function to Node.js tests',
  }),
  debug: flag({
    alias: '--node-arg=--debug',
    description: 'Run JavaScript tests with node --debug',
  }),
  'debug-brk': flag({
    alias: '--node-arg=--debug-brk',
    description: 'Run JavaScript tests with node --debug-brk',
  }),
  harmony: flag({
    alias: '--node-arg=--harmony',
    description: 'Enable all Harmony flags in JavaScript tests',
  }),
  strict: flag({
    alias: '--node-arg=--use-strict',
    description: `Run JS tests in 'use strict' mode`,
  }),

  esm: flag({
    default: process.env.TAP_NO_ESM !== '1',
    description: `Run .js and .mjs with support for EcmaScript modules
                  (Default: true)`,
  }),
  flow: flag({
    description: `Removes flow types`,
  }),

  ts: flag({
    default: process.env.TAP_NO_TS !== '1',
    description: `Automatically load .ts and .tsx tests with tap's bundled
                  ts-node module (Default: true)`,
  }),

  jsx: flag({
    default: process.env.TAP_NO_JSX !== '1',
    description: `Automatically load .jsx tests using tap's bundled import-jsx
                  loader (Default: true)`,
  }),

  'nyc-help': flag({
    description: `Print nyc usage banner.  Useful for
                  viewing options for --nyc-arg.`,
  }),

  'nyc-version': flag({
    description: 'Print version of nyc used by tap.',
  }),

  'parser-version': flag({
    description: 'Print the version of tap-parser used by tap.',
  }),

  versions: flag({
    description: 'Print versions of tap, nyc, and tap-parser',
  }),

  'dump-config': flag({
    description: 'Dump the config options in YAML format',
  }),

  rcfile: opt({
    hint: 'file',
    description: `Load any of these configurations from a YAML-formatted
                  file at the path specified.  Defaults to .taprc in the
                  current working directory.

                  Run 'tap --dump-config' to see available options and
                  formatting.`,
    envDefault: 'TAP_RCFILE',
    default: `${process.cwd()}/.taprc`,
  }),

  'output-file': opt({
    short: 'o',
    hint: 'file',
    default: null,
    description: `Send the raw TAP output to the specified
                  file.  Reporter output will still be
                  printed to stdout, but the file will
                  contain the raw TAP for later replay or
                  analysis.`,
  }),

  'output-dir': opt({
    short: 'd',
    hint: 'dir',
    default: null,
    description: `Send the raw TAP output to the specified
                  directory.  A separate .tap file will be created
                  for each test file that is run.  Reporter output
                  will still be printed to stdout, but the files
                  will contain the raw TAP for later replay or
                  analysis.

                  Files will be created to match the folder structure
                  and filenames of test files run, but with '.tap'
                  appended to the filenames.`,
  }),

  debug: flag({
    envDefault: 'TAP_DEBUG',
    description: 'Turn on debug mode',
  }),

  '--': flag({
    description: `Stop parsing flags, and treat any additional
                  command line arguments as filenames.`
  }),

}, {

  description: 'Environment Variables',

  COVERALLS_REPO_TOKEN: env({
    description: `Set to a Coveralls token to automatically
                  send coverage information to https://coveralls.io`,
    implies: {
      coverage: true
    },
    default: null,
  }),

  TAP_CHILD_ID: env(num({
    description: `Test files have this value set to a
                  numeric value when run through the test
                  runner.  It also appears on the root tap
                  object as \`tap.childId\`.`,
  })),

  TAP_SNAPSHOT: env(flag({
    description: `Set to '1' to generate snapshot files
                  for 't.matchSnapshot()' assertions.`,
  })),

  TAP_RCFILE: env({
    description: `A yaml formatted file which can set any
                  of the above options.  Defaults to
                  ./.taprc`
  }),

  TAP_TIMEOUT: env(num({
    min: 0,
    default: 30,
    description: `Default value for --timeout option.`
  })),

  TAP_COLORS: env(flag({
    description: `Set to '1' to force color output, or '0'
                  to prevent color output.`
  })),

  TAP_BAIL: flag(env({
    description: `Bail out on the first test failure.
                  Used internally when '--bailout' is set.`
  })),

  TAP: flag(env({
    implies: {
      reporter: 'tap'
    },
    description: `Set to '1' to force standard TAP output,
                  and suppress any reporters.  Used when
                  running child tests so that their output
                  is parseable by the test harness.`
  })),

  TAP_DIAG: env(flag({
    description: `Set to '1' to show diagnostics by
                  default for passing tests.  Set to '0'
                  to NOT show diagnostics by default for
                  failing tests.  If not one of these two
                  values, then diagnostics are printed by
                  default for failing tests, and not for
                  passing tests.`
  })),

  TAP_BUFFER: env(flag({
    description: `Set to '1' to run subtests in buffered
                  mode by default.`
  })),

  TAP_DEV_LONGSTACK: env(flag({
    description: `Set to '1' to include node-tap internals
                  in stack traces.  By default, these are
                  included only when the current working
                  directory is the tap project itself.
                  Note that node internals are always
                  excluded.`
  })),

  TAP_DEV_SHORTSTACK: env(flag({
    description: `Set to '1' to exclude node-tap internals
                  in stack traces, even if the current
                  working directory is the tap project
                  itself.`
  })),

  TAP_DEBUG: env(flag({
    description: `Set to '1' to turn on debug mode.`
  })),

  NODE_DEBUG: env({
    description: `Include 'tap' to turn on debug mode.`
  }),

  TAP_GREP: env(list({
    delimiter: '\n',
    description: `A '\\n'-delimited list of grep patterns
                  to apply to root level test objects.
                  (This is an implementation detail for how
                  the '--grep' option works.)`
  })),

  TAP_GREP_INVERT: env(flag({
    description: `Set to '1' to invert the meaning of the
                  patterns in TAP_GREP.  (Implementation
                  detail for how the '--invert' flag
                  works.)`
  })),

  TAP_ONLY: env(flag({
    description: `Set to '1' to set the --only flag`
  })),

  TAP_NO_ESM: env(flag({
    description: `Set to '1' to disable automatic esm support`
  })),

  TAP_NO_TS: env(flag({
    description: `Set to '1' to disable automatic typescript support`
  })),

  TAP_NO_JSX: env(flag({
    description: `Set to '1' to disable automatic jsx support`
  })),

}, {

  // a section that's just a description.  This is totally fine.
  // You can break up the usage output this way.
  description: 'Config Files',
  help: `You can create a yaml file with any of the options above.  By
         default, the file at ./.taprc will be loaded, but the
         --rcfile option or TAP_RCFILE environment variable can modify this.

         Run 'tap --dump-config' for a listing of what can be set in that
         file.  Each of the keys corresponds to one of the options above.`,
})