Atlas › Test

argsert.mjs|title=Argsert warns if required argument is of wrong type|occurrence=1

Exact test identity: mocha:v1|namespace=yargs@4153e0f097aeaf43a71a2530db6dda51dff2c544:main|file=test/argsert.mjs|title=Argsert warns if required argument is of wrong type|occurrence=1

Package
mocha:v1|namespace=yargs@4153e0f097aeaf43a71a2530db6dda51dff2c544:main|file=test
Suite / test hierarchy
argsert.mjs|title=Argsert warns if required argument is of wrong type|occurrence=1
Test
argsert.mjs|title=Argsert warns if required argument is of wrong type|occurrence=1
Introduced at
argsert.mjs|title=Argsert warns if required argument is of wrong type|occurrence=1 Frontier kind: Test frontier
Covered ranges
28
Covered lines
129
Covered files
3

Covered source

Expand a file to inspect source; the > gutter marks covered lines.

lib/argsert.ts 80 covered LOC · 18 ranges

Open complete file

1 > import {YError} from './yerror.js'; argsert.ts
2 > import {parseCommand, ParsedCommand} from './parse-command.js';
3 >
4 > const positionName = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth'];
5 > export function argsert(callerArguments: any[], length?: number): void;
6 > export function argsert(
7 > expected: string,
8 > callerArguments: any[],
9 > length?: number
10 > ): void;
11 > export function argsert(
12 > arg1: string | any[], argsert.ts
13 > arg2?: any[] | number,
14 > arg3?: number
15 > ): void {
16 > function parseArgs(): [
17 > Pick<ParsedCommand, 'demanded' | 'optional'>,
18 > any[],
19 > number?,
20 > ] {
21 > return typeof arg1 === 'object'
22 > ? [{demanded: [], optional: []}, arg1, arg2 as number | undefined]
23 > : [
24 > parseCommand(`cmd ${arg1}`), argsert.ts
25 > arg2 as any[],
26 > arg3 as number | undefined,
27 > ];
28 > } argsert.ts
29 > // TODO: should this eventually raise an exception.
30 > try {
31 > // preface the argument description with "cmd", so
32 > // that we can run it through yargs' command parser.
33 > let position = 0;
34 > const [parsed, callerArguments, _length] = parseArgs();
35 > const args = [].slice.call(callerArguments);
36 >
37 > while (args.length && args[args.length - 1] === undefined) args.pop();
38 > const length = _length || args.length;
39 >
40 > if (length < parsed.demanded.length) {
41 throw new YError(
42 `Not enough arguments provided. Expected ${parsed.demanded.length} but received ${args.length}.`
43 );
44 }
45 > argsert.ts
46 > const totalCommands = parsed.demanded.length + parsed.optional.length;
47 > if (length > totalCommands) {
48 throw new YError(
49 `Too many arguments provided. Expected max ${totalCommands} but received ${length}.`
50 );
51 }
52 > argsert.ts
53 > parsed.demanded.forEach(demanded => {
54 > const arg = args.shift(); argsert.ts
55 > const observedType = guessType(arg);
56 > const matchingTypes = demanded.cmd.filter(
57 > type => type === observedType || type === '*'
58 > );
59 > if (matchingTypes.length === 0)
60 > argumentTypeError(observedType, demanded.cmd, position);
61 position += 1;
62 > }); argsert.ts
63 >
64 > parsed.optional.forEach(optional => {
65 if (args.length === 0) return;
66 const arg = args.shift();
72 argumentTypeError(observedType, optional.cmd, position);
73 position += 1;
74 > }); argsert.ts
75 > } catch (err) { argsert.ts
76 > console.warn((err as Error).stack); argsert.ts
77 > }
78 > } argsert.ts
79 > argsert.ts
80 > function guessType(arg: any) { argsert.ts
81 > if (Array.isArray(arg)) {
82 return 'array';
83 > } else if (arg === null) { argsert.ts
84 return 'null';
85 }
86 > return typeof arg; argsert.ts
87 > }
88 > argsert.ts
89 > function argumentTypeError( argsert.ts
90 > observedType: string,
91 > allowedTypes: string[],
92 > position: number
93 > ) {
94 > throw new YError(
95 > `Invalid ${
96 > positionName[position] || 'manyith'
97 > } argument. Expected ${allowedTypes.join(
98 > ' or '
99 > )} but received ${observedType}.`
100 > );
101 > }
lib/parse-command.ts 40 covered LOC · 7 ranges

Open complete file

1 > import {NotEmptyArray} from './typings/common-types.js'; parse-command.ts
2 >
3 > export function parseCommand(cmd: string) {
4 > const extraSpacesStrippedCommand = cmd.replace(/\s{2,}/g, ' '); parse-command.ts
5 > const splitCommand = extraSpacesStrippedCommand.split(/\s+(?![^[]*]|[^<]*>)/);
6 > const bregex = /\.*[\][<>]/g;
7 >
8 > const firstCommand = splitCommand.shift();
9 > if (!firstCommand) throw new Error(`No command found in: ${cmd}`);
11 > const parsedCommand: ParsedCommand = {
12 > cmd: firstCommand.replace(bregex, ''),
13 > demanded: [],
14 > optional: [],
15 > };
16 > splitCommand.forEach((cmd, i) => {
17 > let variadic = false;
18 > cmd = cmd.replace(/\s/g, '');
19 > if (/\.+[\]>]/.test(cmd) && i === splitCommand.length - 1) variadic = true;
20 > if (/^\[/.test(cmd)) {
21 parsedCommand.optional.push({
22 cmd: cmd.replace(bregex, '').split('|') as NotEmptyArray<string>,
23 variadic,
24 });
25 > } else { parse-command.ts
26 > parsedCommand.demanded.push({ parse-command.ts
27 > cmd: cmd.replace(bregex, '').split('|') as NotEmptyArray<string>,
28 > variadic,
29 > });
30 > }
31 > }); parse-command.ts
32 > return parsedCommand;
33 > }
35 > export interface ParsedCommand {
36 > cmd: string;
37 > demanded: Positional[];
38 > optional: Positional[];
39 > }
40 >
41 > export interface Positional {
42 > cmd: NotEmptyArray<string>;
43 > variadic: boolean;
44 > }
lib/yerror.ts 9 covered LOC · 3 ranges

Open complete file

1 > export class YError extends Error { yerror.ts
2 > name = 'YError';
3 > constructor(msg?: string | null) {
4 > super(msg || 'yargs error'); yerror.ts
5 > if (Error.captureStackTrace) {
6 > Error.captureStackTrace(this, YError);
7 > }
8 > }
9 > } yerror.ts