From a4bb8bab44cc778e6e455f19fdae9f3e4acc809b Mon Sep 17 00:00:00 2001 From: Yusuke Sakurai Date: Sun, 9 Feb 2020 05:15:59 +0900 Subject: [PATCH] remove non-null assertion operator from std (part2) (#3927) --- std/archive/tar.ts | 43 +++++++++++++++++++----------- std/datetime/mod.ts | 2 +- std/encoding/csv.ts | 25 ++++++++++++------ std/encoding/csv_test.ts | 4 +-- std/encoding/toml.ts | 20 +++++++++----- std/flags/mod.ts | 51 +++++++++++++++++++++--------------- std/fs/copy.ts | 48 +++++++++++++++++++++------------ std/fs/expand_glob.ts | 2 +- std/http/file_server_test.ts | 4 ++- std/io/bufio.ts | 2 +- std/log/mod.ts | 2 +- 11 files changed, 128 insertions(+), 75 deletions(-) diff --git a/std/archive/tar.ts b/std/archive/tar.ts index 15d7fe6e8b..33a9ae0974 100644 --- a/std/archive/tar.ts +++ b/std/archive/tar.ts @@ -28,6 +28,7 @@ */ import { MultiReader } from "../io/readers.ts"; import { BufReader } from "../io/bufio.ts"; +import { assert } from "../testing/asserts.ts"; const recordSize = 512; const ustar = "ustar\u000000"; @@ -271,16 +272,17 @@ export class Tar { /** * Append a file to this tar archive - * @param fileName file name + * @param fn file name * e.g., test.txt; use slash for directory separators * @param opts options */ - async append(fileName: string, opts: TarOptions): Promise { - if (typeof fileName !== "string") + async append(fn: string, opts: TarOptions): Promise { + if (typeof fn !== "string") { throw new Error("file name not specified"); - + } + let fileName = fn; // separate file name into two parts if needed - let fileNamePrefix: string; + let fileNamePrefix: string | undefined; if (fileName.length > 100) { let i = fileName.length; while (i >= 0) { @@ -292,19 +294,26 @@ export class Tar { } i--; } - if (i < 0 || fileName.length > 100 || fileNamePrefix!.length > 155) { - throw new Error( - "ustar format does not allow a long file name (length of [file name" + - "prefix] + / + [file name] must be shorter than 256 bytes)" - ); + const errMsg = + "ustar format does not allow a long file name (length of [file name" + + "prefix] + / + [file name] must be shorter than 256 bytes)"; + if (i < 0 || fileName.length > 100) { + throw new Error(errMsg); + } else { + assert(fileNamePrefix != null); + if (fileNamePrefix.length > 155) { + throw new Error(errMsg); + } } } - fileNamePrefix = fileNamePrefix!; opts = opts || {}; // set meta data - const info = opts.filePath && (await Deno.stat(opts.filePath)); + let info: Deno.FileInfo | undefined; + if (opts.filePath) { + info = await Deno.stat(opts.filePath); + } const mode = opts.fileMode || (info && info.mode) || parseInt("777", 8) & 0xfff, @@ -325,13 +334,15 @@ export class Tar { ); } + const fileSize = info?.len ?? opts.contentSize; + assert(fileSize != null, "fileSize must be set"); const tarData: TarDataWithSource = { fileName, fileNamePrefix, fileMode: pad(mode, 7), uid: pad(uid, 7), gid: pad(gid, 7), - fileSize: pad((info ? info.len : opts.contentSize)!, 11), + fileSize: pad(fileSize, 11), mtime: pad(mtime, 11), checksum: " ", type: "0", // just a file @@ -368,16 +379,18 @@ export class Tar { const headerArr = formatHeader(tarData); readers.push(new Deno.Buffer(headerArr)); if (!reader) { - reader = new FileReader(filePath!); + assert(filePath != null); + reader = new FileReader(filePath); } readers.push(reader); // to the nearest multiple of recordSize + assert(tarData.fileSize != null, "fileSize must be set"); readers.push( new Deno.Buffer( clean( recordSize - - (parseInt(tarData.fileSize!, 8) % recordSize || recordSize) + (parseInt(tarData.fileSize, 8) % recordSize || recordSize) ) ) ); diff --git a/std/datetime/mod.ts b/std/datetime/mod.ts index 807a99617f..124f739116 100644 --- a/std/datetime/mod.ts +++ b/std/datetime/mod.ts @@ -1,6 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { pad } from "../strings/pad.ts"; -import { assert } from "../testing/mod.ts"; +import { assert } from "../testing/asserts.ts"; export type DateFormat = "mm-dd-yyyy" | "dd-mm-yyyy" | "yyyy-mm-dd"; diff --git a/std/encoding/csv.ts b/std/encoding/csv.ts index cc486641b5..1314afcaaf 100644 --- a/std/encoding/csv.ts +++ b/std/encoding/csv.ts @@ -5,6 +5,7 @@ import { BufReader } from "../io/bufio.ts"; import { TextProtoReader } from "../textproto/mod.ts"; import { StringReader } from "../io/readers.ts"; +import { assert } from "../testing/asserts.ts"; const INVALID_RUNE = ["\r", "\n", '"']; @@ -37,11 +38,15 @@ export interface ReadOptions { } function chkOptions(opt: ReadOptions): void { - if (!opt.comma) opt.comma = ","; - if (!opt.trimLeadingSpace) opt.trimLeadingSpace = false; + if (!opt.comma) { + opt.comma = ","; + } + if (!opt.trimLeadingSpace) { + opt.trimLeadingSpace = false; + } if ( - INVALID_RUNE.includes(opt.comma!) || - INVALID_RUNE.includes(opt.comment!) || + INVALID_RUNE.includes(opt.comma) || + INVALID_RUNE.includes(opt.comment) || opt.comma === opt.comment ) { throw new Error("Invalid Delimiter"); @@ -81,7 +86,8 @@ async function read( return []; } - result = line.split(opt.comma!); + assert(opt.comma != null); + result = line.split(opt.comma); let quoteError = false; result = result.map((r): string => { @@ -141,7 +147,7 @@ export async function readMatrix( } if (lineResult.length > 0) { - if (_nbFields! && _nbFields! !== lineResult.length) { + if (_nbFields && _nbFields !== lineResult.length) { throw new ParseError(lineIndex, lineIndex, "wrong number of fields"); } result.push(lineResult); @@ -215,7 +221,9 @@ export async function parse( ); } } else { - headers = r.shift()!.map( + const head = r.shift(); + assert(head != null); + headers = head.map( (e): HeaderOptions => { return { name: e @@ -245,7 +253,8 @@ export async function parse( }); } if (opt.parse) { - return r.map((e: string[]): unknown => opt.parse!(e)); + assert(opt.parse != null, "opt.parse must be set"); + return r.map((e: string[]): unknown => opt.parse(e)); } return r; } diff --git a/std/encoding/csv_test.ts b/std/encoding/csv_test.ts index daa30d0fbc..6c726835e9 100644 --- a/std/encoding/csv_test.ts +++ b/std/encoding/csv_test.ts @@ -477,7 +477,7 @@ for (const t of testCases) { if (t.Error) { let err; try { - actual = await readMatrix(new BufReader(new StringReader(t.Input!)), { + actual = await readMatrix(new BufReader(new StringReader(t.Input)), { comma: comma, comment: comment, trimLeadingSpace: trim, @@ -490,7 +490,7 @@ for (const t of testCases) { assert(err); assertEquals(err.message, t.Error); } else { - actual = await readMatrix(new BufReader(new StringReader(t.Input!)), { + actual = await readMatrix(new BufReader(new StringReader(t.Input)), { comma: comma, comment: comment, trimLeadingSpace: trim, diff --git a/std/encoding/toml.ts b/std/encoding/toml.ts index 6af31a1a19..53b907fbfd 100644 --- a/std/encoding/toml.ts +++ b/std/encoding/toml.ts @@ -1,6 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { deepAssign } from "../util/deep_assign.ts"; import { pad } from "../strings/pad.ts"; +import { assert } from "../testing/asserts.ts"; class KeyValuePair { constructor(public key: string, public value: unknown) {} @@ -138,15 +139,16 @@ class Parser { } } _groupToOutput(): void { - const arrProperty = this.context - .currentGroup!.name.replace(/"/g, "") + assert(this.context.currentGroup != null, "currentGroup must be set"); + const arrProperty = this.context.currentGroup.name + .replace(/"/g, "") .replace(/'/g, "") .split("."); let u = {}; - if (this.context.currentGroup!.type === "array") { - u = this._unflat(arrProperty, this.context.currentGroup!.arrValues); + if (this.context.currentGroup.type === "array") { + u = this._unflat(arrProperty, this.context.currentGroup.arrValues); } else { - u = this._unflat(arrProperty, this.context.currentGroup!.objValues); + u = this._unflat(arrProperty, this.context.currentGroup.objValues); } deepAssign(this.context.output, u); delete this.context.currentGroup; @@ -170,10 +172,14 @@ class Parser { } let type; - let name = line.match(captureReg)![1]; + let m = line.match(captureReg); + assert(m != null, "line mut be matched"); + let name = m[1]; if (name.match(/\[.*\]/)) { type = "array"; - name = name.match(captureReg)![1]; + m = name.match(captureReg); + assert(m != null, "name must be matched"); + name = m[1]; } else { type = "object"; } diff --git a/std/flags/mod.ts b/std/flags/mod.ts index 5f4b18a188..9bc4e8cdf5 100644 --- a/std/flags/mod.ts +++ b/std/flags/mod.ts @@ -1,12 +1,14 @@ +import { assert } from "../testing/asserts.ts"; + // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. export interface ArgParsingOptions { - unknown?: (i: unknown) => unknown; - boolean?: boolean | string | string[]; - alias?: { [key: string]: string | string[] }; - string?: string | string[]; - default?: { [key: string]: unknown }; - "--"?: boolean; - stopEarly?: boolean; + unknown: (i: unknown) => unknown; + boolean: boolean | string | string[]; + alias: { [key: string]: string | string[] }; + string: string | string[]; + default: { [key: string]: unknown }; + "--": boolean; + stopEarly: boolean; } const DEFAULT_OPTIONS = { @@ -35,6 +37,11 @@ function get(obj: { [s: string]: T }, key: string): T | undefined { return obj[key]; } } +function getForce(obj: { [s: string]: T }, key: string): T { + const v = get(obj, key); + assert(v != null); + return v; +} function isNumber(x: unknown): boolean { if (typeof x === "number") return true; @@ -55,18 +62,18 @@ function hasKey(obj: NestedMapping, keys: string[]): boolean { export function parse( // eslint-disable-next-line @typescript-eslint/no-explicit-any args: any[], - initialOptions?: ArgParsingOptions + initialOptions: Partial = {} // eslint-disable-next-line @typescript-eslint/no-explicit-any ): { [key: string]: any } { const options: ArgParsingOptions = { ...DEFAULT_OPTIONS, - ...(initialOptions || {}) + ...initialOptions }; const flags: Flags = { bools: {}, strings: {}, - unknownFn: options.unknown!, + unknownFn: options.unknown, allBools: false }; @@ -88,15 +95,13 @@ 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 = getForce(options.alias, key); if (typeof val === "string") { aliases[key] = [val]; } else { aliases[key] = val; } - - for (const alias of get(aliases, key)!) { + for (const alias of getForce(aliases, key)) { aliases[alias] = [key].concat( aliases[key].filter((y: string): boolean => alias !== y) ); @@ -119,7 +124,7 @@ export function parse( }); } - const defaults = options.default!; + const defaults = options.default; const argv: { [key: string]: unknown[] } = { _: [] }; @@ -173,8 +178,8 @@ export function parse( } function aliasIsBoolean(key: string): boolean { - return get(aliases, key)!.some(function(x): boolean { - return get(flags.bools, x)!; + return getForce(aliases, key).some(function(x): boolean { + return typeof get(flags.bools, x) === "boolean"; }); } @@ -197,7 +202,8 @@ export function parse( // Using [\s\S] instead of . because js doesn't support the // 'dotall' regex modifier. See: // http://stackoverflow.com/a/1068308/13216 - const m = arg.match(/^--([^=]+)=([\s\S]*)$/)!; + const m = arg.match(/^--([^=]+)=([\s\S]*)$/); + assert(m != null); const key = m[1]; const value = m[2]; @@ -208,10 +214,13 @@ export function parse( setArg(key, value, arg); } } else if (/^--no-.+/.test(arg)) { - const key = arg.match(/^--no-(.+)/)![1]; - setArg(key, false, arg); + const m = arg.match(/^--no-(.+)/); + assert(m != null); + setArg(m[1], false, arg); } else if (/^--.+/.test(arg)) { - const key = arg.match(/^--(.+)/)![1]; + const m = arg.match(/^--(.+)/); + assert(m != null); + const key = m[1]; const next = args[i + 1]; if ( next !== undefined && diff --git a/std/fs/copy.ts b/std/fs/copy.ts index 44d3a51e23..62e6f59e54 100644 --- a/std/fs/copy.ts +++ b/std/fs/copy.ts @@ -2,6 +2,7 @@ import * as path from "../path/mod.ts"; import { ensureDir, ensureDirSync } from "./ensure_dir.ts"; import { isSubdir, getFileInfoType } from "./utils.ts"; +import { assert } from "../testing/asserts.ts"; export interface CopyOptions { /** @@ -22,8 +23,8 @@ async function ensureValidCopy( dest: string, options: CopyOptions, isCopyFolder = false -): Promise { - let destStat: Deno.FileInfo | null; +): Promise { + let destStat: Deno.FileInfo; try { destStat = await Deno.lstat(dest); @@ -31,6 +32,7 @@ async function ensureValidCopy( if (err instanceof Deno.DenoError && err.kind == Deno.ErrorKind.NotFound) { return; } + throw err; } if (isCopyFolder && !destStat.isDirectory()) { @@ -42,7 +44,7 @@ async function ensureValidCopy( throw new Error(`'${dest}' already exists.`); } - return destStat!; + return destStat; } function ensureValidCopySync( @@ -50,18 +52,18 @@ function ensureValidCopySync( dest: string, options: CopyOptions, isCopyFolder = false -): Deno.FileInfo { - let destStat: Deno.FileInfo | null; - +): Deno.FileInfo | undefined { + let destStat: Deno.FileInfo; try { destStat = Deno.lstatSync(dest); } catch (err) { if (err instanceof Deno.DenoError && err.kind == Deno.ErrorKind.NotFound) { return; } + throw err; } - if (isCopyFolder && !destStat!.isDirectory()) { + if (isCopyFolder && !destStat.isDirectory()) { throw new Error( `Cannot overwrite non-directory '${dest}' with directory '${src}'.` ); @@ -70,7 +72,7 @@ function ensureValidCopySync( throw new Error(`'${dest}' already exists.`); } - return destStat!; + return destStat; } /* copy file to dest */ @@ -83,7 +85,7 @@ async function copyFile( await Deno.copyFile(src, dest); if (options.preserveTimestamps) { const statInfo = await Deno.stat(src); - await Deno.utime(dest, statInfo.accessed!, statInfo.modified!); + await Deno.utime(dest, statInfo.accessed, statInfo.modified); } } /* copy file to dest synchronously */ @@ -92,7 +94,9 @@ function copyFileSync(src: string, dest: string, options: CopyOptions): void { Deno.copyFileSync(src, dest); if (options.preserveTimestamps) { const statInfo = Deno.statSync(src); - Deno.utimeSync(dest, statInfo.accessed!, statInfo.modified!); + assert(statInfo.accessed != null, `statInfo.accessed is unavailable`); + assert(statInfo.modified != null, `statInfo.modified is unavailable`); + Deno.utimeSync(dest, statInfo.accessed, statInfo.modified); } } @@ -108,7 +112,9 @@ async function copySymLink( await Deno.symlink(originSrcFilePath, dest, type); if (options.preserveTimestamps) { const statInfo = await Deno.lstat(src); - await Deno.utime(dest, statInfo.accessed!, statInfo.modified!); + assert(statInfo.accessed != null, `statInfo.accessed is unavailable`); + assert(statInfo.modified != null, `statInfo.modified is unavailable`); + await Deno.utime(dest, statInfo.accessed, statInfo.modified); } } @@ -124,7 +130,9 @@ function copySymlinkSync( Deno.symlinkSync(originSrcFilePath, dest, type); if (options.preserveTimestamps) { const statInfo = Deno.lstatSync(src); - Deno.utimeSync(dest, statInfo.accessed!, statInfo.modified!); + assert(statInfo.accessed != null, `statInfo.accessed is unavailable`); + assert(statInfo.modified != null, `statInfo.modified is unavailable`); + Deno.utimeSync(dest, statInfo.accessed, statInfo.modified); } } @@ -142,13 +150,16 @@ async function copyDir( if (options.preserveTimestamps) { const srcStatInfo = await Deno.stat(src); - await Deno.utime(dest, srcStatInfo.accessed!, srcStatInfo.modified!); + assert(srcStatInfo.accessed != null, `statInfo.accessed is unavailable`); + assert(srcStatInfo.modified != null, `statInfo.modified is unavailable`); + await Deno.utime(dest, srcStatInfo.accessed, srcStatInfo.modified); } const files = await Deno.readDir(src); for (const file of files) { - const srcPath = path.join(src, file.name!); + assert(file.name != null, "file.name must be set"); + const srcPath = path.join(src, file.name); const destPath = path.join(dest, path.basename(srcPath as string)); if (file.isDirectory()) { await copyDir(srcPath, destPath, options); @@ -162,7 +173,7 @@ async function copyDir( /* copy folder from src to dest synchronously */ function copyDirSync(src: string, dest: string, options: CopyOptions): void { - const destStat: Deno.FileInfo = ensureValidCopySync(src, dest, options, true); + const destStat = ensureValidCopySync(src, dest, options, true); if (!destStat) { ensureDirSync(dest); @@ -170,13 +181,16 @@ function copyDirSync(src: string, dest: string, options: CopyOptions): void { if (options.preserveTimestamps) { const srcStatInfo = Deno.statSync(src); - Deno.utimeSync(dest, srcStatInfo.accessed!, srcStatInfo.modified!); + assert(srcStatInfo.accessed != null, `statInfo.accessed is unavailable`); + assert(srcStatInfo.modified != null, `statInfo.modified is unavailable`); + Deno.utimeSync(dest, srcStatInfo.accessed, srcStatInfo.modified); } const files = Deno.readDirSync(src); for (const file of files) { - const srcPath = path.join(src, file.name!); + assert(file.name != null, "file.name must be set"); + const srcPath = path.join(src, file.name); const destPath = path.join(dest, path.basename(srcPath as string)); if (file.isDirectory()) { copyDirSync(srcPath, destPath, options); diff --git a/std/fs/expand_glob.ts b/std/fs/expand_glob.ts index 656852ebb4..aabf4a8a1b 100644 --- a/std/fs/expand_glob.ts +++ b/std/fs/expand_glob.ts @@ -9,7 +9,7 @@ import { normalize } from "../path/mod.ts"; import { WalkInfo, walk, walkSync } from "./walk.ts"; -import { assert } from "../testing/mod.ts"; +import { assert } from "../testing/asserts.ts"; const { ErrorKind, cwd, stat, statSync } = Deno; type ErrorKind = Deno.ErrorKind; type DenoError = Deno.DenoError; diff --git a/std/http/file_server_test.ts b/std/http/file_server_test.ts index 924ee520c9..099723b878 100644 --- a/std/http/file_server_test.ts +++ b/std/http/file_server_test.ts @@ -1,5 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { test } from "../testing/mod.ts"; +import { test, runIfMain } from "../testing/mod.ts"; import { assert, assertEquals, assertStrContains } from "../testing/asserts.ts"; import { BufReader } from "../io/bufio.ts"; import { TextProtoReader } from "../textproto/mod.ts"; @@ -135,3 +135,5 @@ test(async function printHelp(): Promise { helpProcess.close(); helpProcess.stdout.close(); }); + +runIfMain(import.meta); diff --git a/std/io/bufio.ts b/std/io/bufio.ts index 5f0d53eb85..f721022f30 100644 --- a/std/io/bufio.ts +++ b/std/io/bufio.ts @@ -345,7 +345,7 @@ export class BufReader implements Reader { try { await this._fill(); } catch (err) { - err.partial = slice!; + err.partial = slice; throw err; } } diff --git a/std/log/mod.ts b/std/log/mod.ts index d5eed74793..b89896264f 100644 --- a/std/log/mod.ts +++ b/std/log/mod.ts @@ -6,7 +6,7 @@ import { WriterHandler, FileHandler } from "./handlers.ts"; -import { assert } from "../testing/mod.ts"; +import { assert } from "../testing/asserts.ts"; export class LoggerConfig { level?: string;