From 8981c0a47480ca2b1b501f4def010ca0504ef10e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=B7=E6=B8=A1?= Date: Tue, 3 Sep 2019 16:06:38 +0800 Subject: [PATCH 1/3] parse builtin properties --- flags/mod.ts | 75 ++++++++++++++++++++++++--------------------- flags/parse_test.ts | 7 +++++ 2 files changed, 47 insertions(+), 35 deletions(-) diff --git a/flags/mod.ts b/flags/mod.ts index 0ebaaf52eb15..6423438428ed 100644 --- a/flags/mod.ts +++ b/flags/mod.ts @@ -30,6 +30,15 @@ interface NestedMapping { [key: string]: NestedMapping | unknown; } +function get( + obj: { [s: string]: T } | ArrayLike, + key: PropertyKey +): T { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + return obj[key]; + } +} + function isNumber(x: unknown): boolean { if (typeof x === "number") return true; if (/^0x[0-9a-f]+$/i.test(String(x))) return true; @@ -39,7 +48,7 @@ function isNumber(x: unknown): boolean { function hasKey(obj: NestedMapping, keys: string[]): boolean { let o = obj; keys.slice(0, -1).forEach(function(key: string): void { - o = (o[key] || {}) as NestedMapping; + o = (get(o, key) || {}) as NestedMapping; }); const key = keys[keys.length - 1]; @@ -73,18 +82,16 @@ export function parse( ? [options.boolean] : options.boolean; - booleanArgs.filter(Boolean).forEach( - (key: string): void => { - flags.bools[key] = true; - } - ); + booleanArgs.filter(Boolean).forEach((key: string): void => { + flags.bools[key] = true; + }); } } const aliases: { [key: string]: string[] } = {}; if (options.alias !== undefined) { for (const key in options.alias) { - const val = options.alias[key]; + const val = get(options.alias,key); if (typeof val === "string") { aliases[key] = [val]; @@ -92,7 +99,7 @@ export function parse( aliases[key] = val; } - for (const alias of aliases[key]) { + for (const alias of get(aliases,key)) { aliases[alias] = [key].concat( aliases[key].filter((y: string): boolean => alias !== y) ); @@ -106,12 +113,10 @@ export function parse( stringArgs.filter(Boolean).forEach(function(key): void { flags.strings[key] = true; - if (aliases[key]) { - aliases[key].forEach( - (alias: string): void => { - flags.strings[alias] = true; - } - ); + if (get(aliases,key)) { + get(aliases,key).forEach((alias: string): void => { + flags.strings[alias] = true; + }); } }); } @@ -123,32 +128,32 @@ export function parse( function argDefined(key: string, arg: string): boolean { return ( (flags.allBools && /^--[^=]+$/.test(arg)) || - flags.bools[key] || - !!flags.strings[key] || - !!aliases[key] + get(flags.bools,key) || + !!get(flags.strings,key) || + !!get(aliases,key) ); } function setKey(obj: NestedMapping, keys: string[], value: unknown): void { let o = obj; keys.slice(0, -1).forEach(function(key): void { - if (o[key] === undefined) { + if (get(o,key) === undefined) { o[key] = {}; } - o = o[key] as NestedMapping; + o = get(o,key) as NestedMapping; }); const key = keys[keys.length - 1]; if ( - o[key] === undefined || - flags.bools[key] || - typeof o[key] === "boolean" + get(o,key) === undefined || + get(flags.bools,key) || + typeof get(o,key) === "boolean" ) { o[key] = value; - } else if (Array.isArray(o[key])) { + } else if (Array.isArray(get(o,key))) { (o[key] as unknown[]).push(value); } else { - o[key] = [o[key], value]; + o[key] = [get(o, key), value]; } } @@ -161,17 +166,17 @@ export function parse( if (flags.unknownFn(arg) === false) return; } - const value = !flags.strings[key] && isNumber(val) ? Number(val) : val; + const value = !get(flags.strings,key) && isNumber(val) ? Number(val) : val; setKey(argv, key.split("."), value); - (aliases[key] || []).forEach(function(x): void { + (get(aliases,key) || []).forEach(function(x): void { setKey(argv, x.split("."), value); }); } function aliasIsBoolean(key: string): boolean { - return aliases[key].some(function(x): boolean { - return flags.bools[x]; + return get(aliases,key).some(function(x): boolean { + return get(flags.bools, x); }); } @@ -213,9 +218,9 @@ export function parse( if ( next !== undefined && !/^-/.test(next) && - !flags.bools[key] && + !get(flags.bools,key) && !flags.allBools && - (aliases[key] ? !aliasIsBoolean(key) : true) + (get(aliases,key) ? !aliasIsBoolean(key) : true) ) { setArg(key, next, arg); i++; @@ -223,7 +228,7 @@ export function parse( setArg(key, next === "true", arg); i++; } else { - setArg(key, flags.strings[key] ? "" : true, arg); + setArg(key, get(flags.strings,key) ? "" : true, arg); } } else if (/^-[^-]+/.test(arg)) { const letters = arg.slice(1, -1).split(""); @@ -257,7 +262,7 @@ export function parse( broken = true; break; } else { - setArg(letters[j], flags.strings[letters[j]] ? "" : true, arg); + setArg(letters[j], get(flags.strings,letters[j]) ? "" : true, arg); } } @@ -266,8 +271,8 @@ export function parse( if ( args[i + 1] && !/^(-|--)[^-]/.test(args[i + 1]) && - !flags.bools[key] && - (aliases[key] ? !aliasIsBoolean(key) : true) + !get(flags.bools,key) && + (get(aliases,key) ? !aliasIsBoolean(key) : true) ) { setArg(key, args[i + 1], arg); i++; @@ -275,7 +280,7 @@ export function parse( setArg(key, args[i + 1] === "true", arg); i++; } else { - setArg(key, flags.strings[key] ? "" : true, arg); + setArg(key, get(flags.strings,key) ? "" : true, arg); } } } else { diff --git a/flags/parse_test.ts b/flags/parse_test.ts index 2e154f78c98f..9918ce8bb63d 100755 --- a/flags/parse_test.ts +++ b/flags/parse_test.ts @@ -192,3 +192,10 @@ test(function nestedDottedObjects(): void { }); assertEquals(argv.beep, { boop: true }); }); + +test(function flagBuiltinProperty(): void { + const argv = parse(["--toString", "--valueOf", "foo"]); + assertEquals(argv, { toString: true, valueOf: "foo", _: [] }); + assertEquals(typeof argv.toString, "boolean"); + assertEquals(typeof argv.valueOf, "string"); +}); From f166e220b39bf0b9e06d76cd3ffad8d46cf6bda5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=B7=E6=B8=A1?= Date: Tue, 3 Sep 2019 16:14:32 +0800 Subject: [PATCH 2/3] format --- flags/mod.ts | 65 ++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/flags/mod.ts b/flags/mod.ts index 6423438428ed..e41cc42ddfbf 100644 --- a/flags/mod.ts +++ b/flags/mod.ts @@ -30,10 +30,7 @@ interface NestedMapping { [key: string]: NestedMapping | unknown; } -function get( - obj: { [s: string]: T } | ArrayLike, - key: PropertyKey -): T { +function get(obj: { [s: string]: T } | ArrayLike, key: PropertyKey): T { if (Object.prototype.hasOwnProperty.call(obj, key)) { return obj[key]; } @@ -82,16 +79,18 @@ export function parse( ? [options.boolean] : options.boolean; - booleanArgs.filter(Boolean).forEach((key: string): void => { - flags.bools[key] = true; - }); + booleanArgs.filter(Boolean).forEach( + (key: string): void => { + flags.bools[key] = true; + } + ); } } const aliases: { [key: string]: string[] } = {}; if (options.alias !== undefined) { for (const key in options.alias) { - const val = get(options.alias,key); + const val = get(options.alias, key); if (typeof val === "string") { aliases[key] = [val]; @@ -99,7 +98,7 @@ export function parse( aliases[key] = val; } - for (const alias of get(aliases,key)) { + for (const alias of get(aliases, key)) { aliases[alias] = [key].concat( aliases[key].filter((y: string): boolean => alias !== y) ); @@ -113,10 +112,12 @@ export function parse( stringArgs.filter(Boolean).forEach(function(key): void { flags.strings[key] = true; - if (get(aliases,key)) { - get(aliases,key).forEach((alias: string): void => { - flags.strings[alias] = true; - }); + if (get(aliases, key)) { + get(aliases, key).forEach( + (alias: string): void => { + flags.strings[alias] = true; + } + ); } }); } @@ -128,29 +129,29 @@ export function parse( function argDefined(key: string, arg: string): boolean { return ( (flags.allBools && /^--[^=]+$/.test(arg)) || - get(flags.bools,key) || - !!get(flags.strings,key) || - !!get(aliases,key) + get(flags.bools, key) || + !!get(flags.strings, key) || + !!get(aliases, key) ); } function setKey(obj: NestedMapping, keys: string[], value: unknown): void { let o = obj; keys.slice(0, -1).forEach(function(key): void { - if (get(o,key) === undefined) { + if (get(o, key) === undefined) { o[key] = {}; } - o = get(o,key) as NestedMapping; + o = get(o, key) as NestedMapping; }); const key = keys[keys.length - 1]; if ( - get(o,key) === undefined || - get(flags.bools,key) || - typeof get(o,key) === "boolean" + get(o, key) === undefined || + get(flags.bools, key) || + typeof get(o, key) === "boolean" ) { o[key] = value; - } else if (Array.isArray(get(o,key))) { + } else if (Array.isArray(get(o, key))) { (o[key] as unknown[]).push(value); } else { o[key] = [get(o, key), value]; @@ -166,16 +167,16 @@ export function parse( if (flags.unknownFn(arg) === false) return; } - const value = !get(flags.strings,key) && isNumber(val) ? Number(val) : val; + const value = !get(flags.strings, key) && isNumber(val) ? Number(val) : val; setKey(argv, key.split("."), value); - (get(aliases,key) || []).forEach(function(x): void { + (get(aliases, key) || []).forEach(function(x): void { setKey(argv, x.split("."), value); }); } function aliasIsBoolean(key: string): boolean { - return get(aliases,key).some(function(x): boolean { + return get(aliases, key).some(function(x): boolean { return get(flags.bools, x); }); } @@ -218,9 +219,9 @@ export function parse( if ( next !== undefined && !/^-/.test(next) && - !get(flags.bools,key) && + !get(flags.bools, key) && !flags.allBools && - (get(aliases,key) ? !aliasIsBoolean(key) : true) + (get(aliases, key) ? !aliasIsBoolean(key) : true) ) { setArg(key, next, arg); i++; @@ -228,7 +229,7 @@ export function parse( setArg(key, next === "true", arg); i++; } else { - setArg(key, get(flags.strings,key) ? "" : true, arg); + setArg(key, get(flags.strings, key) ? "" : true, arg); } } else if (/^-[^-]+/.test(arg)) { const letters = arg.slice(1, -1).split(""); @@ -262,7 +263,7 @@ export function parse( broken = true; break; } else { - setArg(letters[j], get(flags.strings,letters[j]) ? "" : true, arg); + setArg(letters[j], get(flags.strings, letters[j]) ? "" : true, arg); } } @@ -271,8 +272,8 @@ export function parse( if ( args[i + 1] && !/^(-|--)[^-]/.test(args[i + 1]) && - !get(flags.bools,key) && - (get(aliases,key) ? !aliasIsBoolean(key) : true) + !get(flags.bools, key) && + (get(aliases, key) ? !aliasIsBoolean(key) : true) ) { setArg(key, args[i + 1], arg); i++; @@ -280,7 +281,7 @@ export function parse( setArg(key, args[i + 1] === "true", arg); i++; } else { - setArg(key, get(flags.strings,key) ? "" : true, arg); + setArg(key, get(flags.strings, key) ? "" : true, arg); } } } else { From 3d3d83b3abbff9045c93a15fa74f853544d271d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=B7=E6=B8=A1?= Date: Tue, 3 Sep 2019 16:41:51 +0800 Subject: [PATCH 3/3] add non-null assertion --- flags/mod.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/flags/mod.ts b/flags/mod.ts index e41cc42ddfbf..e861c54bcdf5 100644 --- a/flags/mod.ts +++ b/flags/mod.ts @@ -30,7 +30,7 @@ interface NestedMapping { [key: string]: NestedMapping | unknown; } -function get(obj: { [s: string]: T } | ArrayLike, key: PropertyKey): T { +function get(obj: { [s: string]: T }, key: string): T | undefined { if (Object.prototype.hasOwnProperty.call(obj, key)) { return obj[key]; } @@ -90,7 +90,7 @@ export function parse( const aliases: { [key: string]: string[] } = {}; if (options.alias !== undefined) { for (const key in options.alias) { - const val = get(options.alias, key); + const val = get(options.alias, key)!; if (typeof val === "string") { aliases[key] = [val]; @@ -98,7 +98,7 @@ export function parse( aliases[key] = val; } - for (const alias of get(aliases, key)) { + for (const alias of get(aliases, key)!) { aliases[alias] = [key].concat( aliases[key].filter((y: string): boolean => alias !== y) ); @@ -112,8 +112,9 @@ export function parse( stringArgs.filter(Boolean).forEach(function(key): void { flags.strings[key] = true; - if (get(aliases, key)) { - get(aliases, key).forEach( + const alias = get(aliases, key); + if (alias) { + alias.forEach( (alias: string): void => { flags.strings[alias] = true; } @@ -176,8 +177,8 @@ export function parse( } function aliasIsBoolean(key: string): boolean { - return get(aliases, key).some(function(x): boolean { - return get(flags.bools, x); + return get(aliases, key)!.some(function(x): boolean { + return get(flags.bools, x)!; }); }