diff --git a/.gitignore b/.gitignore index 5d7b731..74fe7d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /* /.* +!/examples !typedoc.json !tsconfig*.json !.github diff --git a/examples/git-tag.js b/examples/git-tag.js deleted file mode 100644 index 0fbf81d..0000000 --- a/examples/git-tag.js +++ /dev/null @@ -1,82 +0,0 @@ -// usage for git-tag -const { jack, flag, opt } = require('../') -jack({ - usage: [ - 'git tag [-a | -s | -u ] [-f] [-m | -F ] []', - 'git tag -d ...', - 'git tag -l [-n[]] [--contains ] [--points-at ] [...]', - 'git tag -v ...', - ], - list: flag({ - short: 'l', - description: 'list tag names', - negate: { hidden: true }, - }), - n: opt({ - hint: 'n', - description: 'print lines of each tag message', - }), - delete: flag({ - short: 'd', - description: 'delete tags', - negate: { hidden: true }, - }), - verify: flag({ - short: 'v', - description: 'verify tags', - negate: { hidden: true }, - }), - '--': flag({ hidden: true }), - help: flag({ hidden: true }), -}, { - description: 'Tag creation options', - annotate: flag({ - short: 'a', - description: 'annotated tag, needs a message', - }), - message: opt({ - short: 'm', - hint: 'message', - description: 'tag message' - }), - file: opt({ - short: 'F', - hint: 'file', - description: 'read message from file' - }), - sign: flag({ - short: 's', - description: 'annotated and GPG-signed tag' - }), - cleanup: opt({ - hint: 'mode', - description: 'how to strip spaces and #comments from message' - }), - 'local-user': opt({ - short: 'u', - hint: 'key-id', - description: 'use another key to sign the tag', - }), - force: flag({ - short: 'f', - description: 'replace the tag if exists' - }) -}, { - description: 'Tag listing options', - column: opt({ - hint: 'style', - description: 'show tag list in columns', - }), - sort: opt({ - hint: 'type', - description: 'sort tags', - }), - contains: opt({ - hint: 'commit', - description: 'print only tags that contain the commit' - }), - 'points-at': opt({ - hint: 'object', - description: 'print only tags of the object' - }) -}) diff --git a/examples/git-tag.ts b/examples/git-tag.ts new file mode 100644 index 0000000..00aa241 --- /dev/null +++ b/examples/git-tag.ts @@ -0,0 +1,108 @@ +import('../dist/mjs/index.js').then(({ jack }) => { + const j = jack({ + usage: ` +git tag [-a | -s | -u ] [-f] [-m | -F ] [-e] + [ | ] + or: git tag -d ... + or: git tag [-n[]] -l [--contains ] [--no-contains ] + [--points-at ] [--column[=] | --no-column] + [--create-reflog] [--sort=] [--format=] + [--merged ] [--no-merged ] [...] + or: git tag -v [--format=] ... + `, + }) + .flag({ + list: { + short: 'l', + description: 'list tag names', + }, + }) + .opt({ + n: { + hint: 'n', + description: 'print lines of each tag message', + }, + }) + .flag({ + delete: { + short: 'd', + description: 'delete tags', + }, + }) + .flag({ + verify: { + short: 'v', + description: 'verify tags', + negate: { hidden: true }, + }, + }) + .flag({ + help: { + short: 'h', + }, + }) + .description('Tag creation options') + .flag({ + annotate: { + short: 'a', + description: 'annotated tag, needs a message', + }, + }) + .opt({ + message: { + short: 'm', + hint: 'message', + description: 'tag message', + }, + file: { + short: 'F', + hint: 'file', + description: 'read message from file', + }, + }) + .flag({ + sign: { + short: 's', + description: 'annotated and GPG-signed tag', + }, + }) + .opt({ + cleanup: { + hint: 'mode', + description: 'how to strip spaces and #comments from message', + }, + 'local-user': { + short: 'u', + hint: 'key-id', + description: 'use another key to sign the tag', + }, + }) + .flag({ + force: { + short: 'f', + description: 'replace the tag if exists', + }, + }) + .description('Tag listing options') + .opt({ + column: { + hint: 'style', + description: 'show tag list in columns', + }, + sort: { + hint: 'type', + description: 'sort tags', + }, + contains: { + hint: 'commit', + description: 'print only tags that contain the commit', + }, + 'points-at': { + hint: 'object', + description: 'print only tags of the object', + }, + }) + const { values, positionals } = j.parse() + if (values.help) console.log(j.usage()) + else console.log({ values, positionals }) +}) diff --git a/examples/tap.js b/examples/tap.js deleted file mode 100644 index 55603d4..0000000 --- a/examples/tap.js +++ /dev/null @@ -1,516 +0,0 @@ -const { jack, num, opt, list, flag, env } = require('../') -const getReporters = () => [ - 'classic', - 'doc', - 'dot', - 'dump', - 'json', - 'jsonstream', - 'landing', - 'list', - 'markdown', - 'min', - 'nyan', - 'progress', - 'silent', - 'spec', - 'tap', - 'xunit' -] - -const res = jack({ - usage: 'tap [options] ', - help:` -Executes all the files and interprets their output as TAP -formatted test result data. - -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, but -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', - valid: getReporters(), - description: `Use the specified reporter. Defaults to - 'classic' when colors are in use, or 'tap' - when colors are disabled. - - Available reporters: - ${getReporters().join(' ')}`, - }), - - bail: flag({ - short: 'b', - 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', - default: process.stdout.isTTY, - description: 'Use colors (Default for TTY)', - negate: { - short: 'C', - description: 'Do not use colors (Default for non-TTY)' - } - }), - - save: opt({ - short: 's', - hint: 'file', - description: `If exists, then it should be a line- - delimited list of test files to run. If - 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 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', - 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({ - short: 'i', - description: 'Invert the matches to --grep patterns. (Like grep -v)', - negate: { short: 'I' } - }), - - timeout: num({ - envDefault: 'TAP_TIMEOUT', - default: 30, - min: 0, - short: 't', - hint: 'n', - description: `Time out test files after seconds. - Defaults to 30, or the value of the - TAP_TIMEOUT environment variable. - Setting to 0 allows tests to run - forever.`, - }), - - 'no-timeout': flag({ - short: 'T', - alias: '--timeout=0', - description: 'Do not time out tests. Equivalent to --timeout=0.', - }), - -}, { - - 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.`, - - jobs: opt({ - short: 'j', - hint: 'n', - default: 1, - description:`Run up to test files in parallel - Note that this causes tests to be run in - "buffered" mode, so line-by-line results - cannot be reported, and older TAP - parsers may get upset.`, - }), - - 'jobs-auto': flag({ - short: 'J', - alias: '--jobs=' + require('os').cpus().lenght, - description: `Run test files in parallel (auto calculated) - Note that this causes tests to be run in - "buffered" mode, so line-by-line results - cannot be reported, and older TAP - parsers may get upset.`, - }), - -}, { - - 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.`, - }), - - coverage: flag({ - short: 'cov', - description: `Capture coverage information using 'nyc' - - If a COVERALLS_REPO_TOKEN environment - variable is set, then coverage is - captured by default and 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': opt({ - hint: 'type', - 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.`, - }), - - 'no-coverage-report': flag({ - description: `Do not output a coverage report, even if coverage - information is generated.` - }), - - 'no-browser': flag({ - description: `Do not open a web browser after generating - an html coverage report`, - }), -}, { - 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: 0, - hint: 'n', - implies: { - 'check-coverage': true, - coverage: true - }, - description: `what % of branches must be covered?`, - }), - - functions: num({ - min: 0, - max:100, - default: 0, - hint: 'n', - implies: { - 'check-coverage': true, - coverage: true - }, - description: `what % of functions must be covered?`, - }), - - lines: num({ - min: 0, - max:100, - default: 90, - hint: 'n', - implies: { - 'check-coverage': true, - coverage: true - }, - description: `what % of lines must be covered?`, - }), - - statements: num({ - min: 0, - max:100, - default: 0, - 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-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.`, - }), - - '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=--strict', - description: `Run JS tests in 'use strict' mode`, - }), - - '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.', - }), - - 'dump-config': flag({ - description: 'Dump the config options in JSON format', - }), - - 'output-file': opt({ - short: 'o', - hint: 'file', - 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.`, - }), - - '--': flag({ - description: `Stop parsing flags, and treat any additional - command line arguments as filenames.` - }), - -}, { - - description: 'Environment Variables', - - TAP_CHILD_ID: env(flag({ - 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 - $HOME/.taprc` - }), - - TAP_TIMEOUT: env(num({ - min: 0, - 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({ - 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_COVERAGE_: env(flag({ - description: `Reserved for internal use.` - })), - -}, { - - // 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 - 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.`, -}) - -console.log(res._.parsed) -console.log(res) diff --git a/examples/tap.ts b/examples/tap.ts new file mode 100644 index 0000000..93e57bc --- /dev/null +++ b/examples/tap.ts @@ -0,0 +1,427 @@ +import { jack } from '../dist/cjs/index.js' + +import * as os from 'node:os' +const defaultParallel = Math.max( + 16, + typeof os.availableParallelism === 'function' + ? os.availableParallelism() + : Math.min(os.cpus().length, 1) +) + +const coverageReporters = [ + 'clover', + 'cobertura', + 'html', + 'json', + 'json-summary', + 'lcov', + 'lcovonly', + 'none', + 'teamcity', + 'text', + 'text-lcov', + 'text-summary', +] + +const j = jack({ + envPrefix: 'TAP', + allowPositionals: true, + env: process.env, + usage: 'tap [] [ ...[]]', +}) + .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' + + Coverage is not enabled for stdin. + + Much more documentation available at: https://www.node-tap.org/` + ) + .heading('Basic Options') + .optList({ + plugin: { + hint: 'module', + description: `Configure the tap Test class with the specified plugin. + + Typically this is set in a .taprc file, not on the command + line, and can be managed using the 'tap plugin ' + command. + + If the set of plugins does not match that which tap was + built with previously, then it will rebuild the Test class + prior to running tests. + + To *exclude* a plugin which has been previously included + (perhaps by being part of tap's default set), add it to + this list prefixed by a '!' character.`, + }, + }) + + .opt({ + reporter: { + short: 'R', + hint: 'reporter', + 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.`, + }, + }) + + .optList({ + 'reporter-arg': { + hint: 'arg', + short: 'r', + description: `Args to pass to command-line reporters. Ignored when using + built-in reporters or module reporters.`, + }, + }) + + .opt({ + 'coverage-reporter': { + hint: 'type', + description: `Output coverage information using the specified + istanbul coverage 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. + + Built-in coverage reporters: + ${coverageReporters.join(' ')}`, + }, + }) + + .flag({ + // TODO: move to @tapjs/fixture plugin + 'save-fixture': { + short: 'F', + description: 'Do not clean up fixtures created with t.testdir()', + }, + + bail: { + short: 'b', + description: 'Bail out on first failure', + }, + 'no-bail': { + short: 'B', + description: 'Do not bail out on first failure (default)', + }, + + comments: { + description: 'Print all tap comments to process.stderr', + }, + + color: { + short: 'c', + description: 'Use colors (Default for TTY)', + }, + 'no-color': { + short: 'C', + description: 'Do not use colors (Default for non-TTY)', + }, + + // TODO: move to @tapjs/snapshot plugin + snapshot: { + short: 'S', + description: `Generate snapshot files for 't.matchSnapshot()' + assertions.`, + }, + + watch: { + 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: { + short: 'n', + description: `Only run tests for files that have changed since the last + run. + + If no prior test run data exists, then all default files + are run, as if --changed was not specified.`, + }, + + save: { + short: 's', + description: `If exists, then it should be a line- delimited list + of test files to run. If 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 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.`, + }, + + // TODO: move to @tapjs/filter plugin + only: { + short: 'O', + description: `Only run tests with {only: true} option, or created with + t.only(...) function.`, + }, + }) + + .optList({ + // TODO: move to @tapjs/filter plugin + grep: { + hint: 'pattern', + short: 'g', + 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.`, + }, + }) + + .flag({ + // TODO: move to @tapjs/filter plugin + invert: { + short: 'i', + description: 'Invert the matches to --grep patterns. (Like grep -v)', + }, + 'no-invert': { + short: 'I', + description: + 'Do not invert the matches to --grep patterns. (default)', + }, + + diag: { + description: `Set to show diagnostics by default for both passing tests. + If not set, then diagnostics are printed by default for + failing tests, and not for passing tests.`, + }, + 'no-diag': { + description: `Do not show diagnostics by default for passing or failing + tests. If not set, then diagnostics are printed by default + for failing tests, and not for passing tests.`, + }, + }) + .num({ + timeout: { + hint: 'n', + short: 't', + default: 30, + description: `Time out test files after seconds. Defaults to 30. + 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.`, + }, + }) + + .optList({ + files: { + hint: 'filename', + 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.`, + }, + }) + + .heading('Test Running Options') + + .num({ + jobs: { + hint: 'n', + short: 'j', + default: defaultParallel, + description: `Run up to test files in parallel. + + By default, this will be set to the number of CPUs on + the system (${defaultParallel}). + + Set --jobs=1 to disable parallelization entirely.`, + }, + }) + + .opt({ + before: { + 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: { + 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.`, + }, + + 'output-file': { + hint: 'filename', + short: 'o', + 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': { + hint: 'dir', + short: 'd', + 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.`, + }, + + include: { + hint: 'pattern', + default: + '**/{' + + 'test*(s)|__test*(s)__)/**/*,' + + '*.@(test*(s)|spec),' + + 'test*(s)' + + '}.([mc]js|[jt]s*(x))', + description: `A glob expression pattern indicating tests to run if no + positional arguments are provided to the 'tap run' command. + + By default, tap will search for all files ending in .ts, + .tsx, .cts, .mts, .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,...)' + + No files excluded by the 'exclude' option will be loaded, + meaning so dependencies, build artifacts in 'dist', and + test fixtures and snapshots will be ignored.`, + }, + + exclude: { + hint: 'pattern', + default: '**/@(fixture*(s)|dist)/**', + description: `A glob pattern indicating which filenames should NEVER + be run as tests. This overrides the 'include' option. + + Defaults to excluding any folders named dist, fixture, or + fixtures. + + 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.`, + }, + }) + + .optList({ + 'test-arg': { + 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': { + 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, such as '--test-env=key', then + the key is ensured to not be set in the environment. To + set a key to the empty string, use --test-env=key=`, + }, + + 'node-arg': { + hint: 'arg', + // this is one that the mock plugin might want to add to? + // or should we just always force our loaders in? + 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.`, + }, + }) + + .heading('Other Options') + + .flag({ + debug: { description: 'Turn on debug mode' }, + + versions: { + short: 'V', + description: + 'Show the version of tap and relevant tap libraries in use.', + }, + + version: { + short: 'v', + description: 'Show the version of this program.', + }, + + help: { + short: 'h', + type: 'boolean', + description: 'show this help banner', + }, + }) + +try { + const { values, positionals } = j.parse() + if (values.help) console.log(j.usage()) + else { + console.log({ values, positionals }) + console.log( + Object.entries(process.env).filter(([k]) => k.startsWith('TAP')) + ) + } +} catch (e) { + console.error(e) +} diff --git a/package-lock.json b/package-lock.json index 4983f13..80c25e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "2.1.1", "license": "BlueOak-1.0.0", "dependencies": { - "cliui": "^8.0.1" + "cliui": "github:isaacs/cliui#isaacs/esm-cjs-consistency" }, "devDependencies": { "@types/node": "^18.15.11", @@ -1142,17 +1142,93 @@ }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "resolved": "git+ssh://git@github.com/isaacs/cliui.git#f2366630a04255a3bf336f89cf447493ea52e04b", + "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { "node": ">=12" } }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -1285,6 +1361,11 @@ "node": ">=6.0.0" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, "node_modules/electron-to-chromium": { "version": "1.4.356", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.356.tgz", @@ -3098,6 +3179,20 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3109,6 +3204,18 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -5453,6 +5560,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -5465,10 +5573,58 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -5483,6 +5639,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -5493,7 +5650,8 @@ "node_modules/wrap-ansi/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/wrappy": { "version": "1.0.2", @@ -6478,13 +6636,60 @@ "dev": true }, "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "version": "git+ssh://git@github.com/isaacs/cliui.git#f2366630a04255a3bf336f89cf447493ea52e04b", + "from": "cliui@github:isaacs/cliui#isaacs/esm-cjs-consistency", "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } } }, "color-convert": { @@ -6590,6 +6795,11 @@ "esutils": "^2.0.2" } }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, "electron-to-chromium": { "version": "1.4.356", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.356.tgz", @@ -7941,6 +8151,16 @@ "strip-ansi": "^6.0.1" } }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -7949,6 +8169,14 @@ "ansi-regex": "^5.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -9495,6 +9723,43 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", diff --git a/package.json b/package.json index eb0614e..e6a3cfe 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "typescript": "^5.0.2" }, "dependencies": { - "cliui": "^8.0.1" + "cliui": "github:isaacs/cliui#isaacs/esm-cjs-consistency" }, "engines": { "node": ">=14"