From f124e645263099132025256df8594ca0dc5cc83a Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Tue, 12 Mar 2019 14:51:51 +0900 Subject: [PATCH] fix: eslint errors (denoland/deno_std#265) Original: https://github.com/denoland/deno_std/commit/61af419bbc5717c2e2552050aacb20ef1b17480b --- .eslintignore | 3 - .eslintrc.json | 2 +- flags/mod.ts | 92 ++++++------ flags/tests/bool.ts | 3 - flags/tests/parse.ts | 4 +- flags/tests/unknown.ts | 22 +-- format.ts | 2 +- fs/glob_test.ts | 6 +- fs/globrex.ts | 24 +-- fs/globrex_test.ts | 21 ++- fs/path/mod.ts | 4 +- fs/path/parse_format_test.ts | 67 +++++---- fs/walk.ts | 93 ++++++------ fs/walk_test.ts | 32 ++-- http/file_server.ts | 2 +- http/file_server_test.ts | 4 +- http/server.ts | 24 +-- testing/asserts.ts | 2 +- ws/mod.ts | 281 ++++++++++++++++++----------------- ws/sha1.ts | 16 +- 20 files changed, 355 insertions(+), 349 deletions(-) delete mode 100644 .eslintignore diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 93c2c09248..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -/flags/ -/fs/ -/ws/ diff --git a/.eslintrc.json b/.eslintrc.json index 43405e21eb..82e28cfa7e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -17,7 +17,7 @@ "@typescript-eslint/no-parameter-properties": ["off"], "@typescript-eslint/no-unused-vars": [ "error", - { "argsIgnorePattern": "^_" } + { "argsIgnorePattern": "^_", "varsIgnorePattern": "_" } ] } } diff --git a/flags/mod.ts b/flags/mod.ts index 2b91c2775d..0c0702e8bc 100644 --- a/flags/mod.ts +++ b/flags/mod.ts @@ -1,12 +1,12 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. export interface ArgParsingOptions { unknown?: Function; - boolean?: Boolean | string | string[]; + boolean?: boolean | string | string[]; alias?: { [key: string]: string | string[] }; string?: string | string[]; - default?: { [key: string]: any }; - "--"?: Boolean; - stopEarly?: Boolean; + default?: { [key: string]: any }; // eslint-disable-line @typescript-eslint/no-explicit-any + "--"?: boolean; + stopEarly?: boolean; } const DEFAULT_OPTIONS = { @@ -19,10 +19,27 @@ const DEFAULT_OPTIONS = { stopEarly: false }; +function isNumber(x: unknown): boolean { + if (typeof x === "number") return true; + if (/^0x[0-9a-f]+$/i.test(String(x))) return true; + return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(String(x)); +} + +function hasKey(obj, keys): boolean { + let o = obj; + keys.slice(0, -1).forEach(function(key) { + o = o[key] || {}; + }); + + const key = keys[keys.length - 1]; + return key in o; +} + export function parse( args, initialOptions?: ArgParsingOptions ): { [key: string]: any } { + // eslint-disable-line @typescript-eslint/no-explicit-any const options: ArgParsingOptions = { ...DEFAULT_OPTIONS, ...(initialOptions || {}) @@ -72,18 +89,8 @@ export function parse( const defaults = options.default!; const argv = { _: [] }; - Object.keys(flags.bools).forEach(function(key) { - setArg(key, defaults[key] === undefined ? false : defaults[key]); - }); - let notFlags = []; - - if (args.indexOf("--") !== -1) { - notFlags = args.slice(args.indexOf("--") + 1); - args = args.slice(0, args.indexOf("--")); - } - - function argDefined(key, arg) { + function argDefined(key, arg): boolean { return ( (flags.allBools && /^--[^=]+$/.test(arg)) || flags.strings[key] || @@ -92,19 +99,6 @@ export function parse( ); } - function setArg(key, val, arg = null): void { - if (arg && flags.unknownFn && !argDefined(key, arg)) { - if (flags.unknownFn(arg) === false) return; - } - - const value = !flags.strings[key] && isNumber(val) ? Number(val) : val; - setKey(argv, key.split("."), value); - - (aliases[key] || []).forEach(function(x) { - setKey(argv, x.split("."), value); - }); - } - function setKey(obj, keys, value): void { let o = obj; keys.slice(0, -1).forEach(function(key) { @@ -126,12 +120,36 @@ export function parse( } } + function setArg(key, val, arg = null): void { + if (arg && flags.unknownFn && !argDefined(key, arg)) { + if (flags.unknownFn(arg) === false) return; + } + + const value = !flags.strings[key] && isNumber(val) ? Number(val) : val; + setKey(argv, key.split("."), value); + + (aliases[key] || []).forEach(function(x) { + setKey(argv, x.split("."), value); + }); + } + function aliasIsBoolean(key): boolean { return aliases[key].some(function(x) { return flags.bools[x]; }); } + Object.keys(flags.bools).forEach(function(key) { + setArg(key, defaults[key] === undefined ? false : defaults[key]); + }); + + let notFlags = []; + + if (args.indexOf("--") !== -1) { + notFlags = args.slice(args.indexOf("--") + 1); + args = args.slice(0, args.indexOf("--")); + } + for (let i = 0; i < args.length; i++) { const arg = args[i]; @@ -242,7 +260,7 @@ export function parse( }); if (options["--"]) { - argv["--"] = new Array(); + argv["--"] = []; notFlags.forEach(function(key) { argv["--"].push(key); }); @@ -254,19 +272,3 @@ export function parse( return argv; } - -function hasKey(obj, keys) { - let o = obj; - keys.slice(0, -1).forEach(function(key) { - o = o[key] || {}; - }); - - const key = keys[keys.length - 1]; - return key in o; -} - -function isNumber(x: any): boolean { - if (typeof x === "number") return true; - if (/^0x[0-9a-f]+$/i.test(x)) return true; - return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x); -} diff --git a/flags/tests/bool.ts b/flags/tests/bool.ts index 321dbb1e9c..bffb1fd34f 100755 --- a/flags/tests/bool.ts +++ b/flags/tests/bool.ts @@ -39,9 +39,6 @@ test(function booleanGroups() { test(function booleanAndAliasWithChainableApi() { const aliased = ["-h", "derp"]; const regular = ["--herp", "derp"]; - const opts = { - herp: { alias: "h", boolean: true } - }; const aliasedArgv = parse(aliased, { boolean: "herp", alias: { h: "herp" } diff --git a/flags/tests/parse.ts b/flags/tests/parse.ts index 73bdb7c3b3..a37cd4c631 100755 --- a/flags/tests/parse.ts +++ b/flags/tests/parse.ts @@ -178,7 +178,7 @@ test(function nestedDottedObjects() { "4", "--foo.quux.quibble", "5", - "--foo.quux.o_O", + "--foo.quux.oO", "--beep.boop" ]); @@ -187,7 +187,7 @@ test(function nestedDottedObjects() { baz: 4, quux: { quibble: 5, - o_O: true + oO: true } }); assertEquals(argv.beep, { boop: true }); diff --git a/flags/tests/unknown.ts b/flags/tests/unknown.ts index 986bc29d8e..cd944746f0 100755 --- a/flags/tests/unknown.ts +++ b/flags/tests/unknown.ts @@ -5,7 +5,7 @@ import { parse } from "../mod.ts"; test(function booleanAndAliasIsNotUnknown() { const unknown = []; - function unknownFn(arg) { + function unknownFn(arg): boolean { unknown.push(arg); return false; } @@ -16,15 +16,15 @@ test(function booleanAndAliasIsNotUnknown() { boolean: "h", unknown: unknownFn }; - const aliasedArgv = parse(aliased, opts); - const propertyArgv = parse(regular, opts); + parse(aliased, opts); + parse(regular, opts); assertEquals(unknown, ["--derp", "-d"]); }); test(function flagBooleanTrueAnyDoubleHyphenArgumentIsNotUnknown() { const unknown = []; - function unknownFn(arg) { + function unknownFn(arg): boolean { unknown.push(arg); return false; } @@ -41,7 +41,7 @@ test(function flagBooleanTrueAnyDoubleHyphenArgumentIsNotUnknown() { test(function stringAndAliasIsNotUnkown() { const unknown = []; - function unknownFn(arg) { + function unknownFn(arg): boolean { unknown.push(arg); return false; } @@ -52,15 +52,15 @@ test(function stringAndAliasIsNotUnkown() { string: "h", unknown: unknownFn }; - const aliasedArgv = parse(aliased, opts); - const propertyArgv = parse(regular, opts); + parse(aliased, opts); + parse(regular, opts); assertEquals(unknown, ["--derp", "-d"]); }); test(function defaultAndAliasIsNotUnknown() { const unknown = []; - function unknownFn(arg) { + function unknownFn(arg): boolean { unknown.push(arg); return false; } @@ -71,15 +71,15 @@ test(function defaultAndAliasIsNotUnknown() { alias: { h: "herp" }, unknown: unknownFn }; - const aliasedArgv = parse(aliased, opts); - const propertyArgv = parse(regular, opts); + parse(aliased, opts); + parse(regular, opts); assertEquals(unknown, []); }); test(function valueFollowingDoubleHyphenIsNotUnknown() { const unknown = []; - function unknownFn(arg) { + function unknownFn(arg): boolean { unknown.push(arg); return false; } diff --git a/format.ts b/format.ts index d5878f27b9..80bde59ded 100755 --- a/format.ts +++ b/format.ts @@ -4,7 +4,7 @@ const { exit, args, execPath } = Deno; import { parse } from "./flags/mod.ts"; import { xrun } from "./prettier/util.ts"; -async function main(opts) { +async function main(opts): Promise { const args = [ execPath, "--allow-write", diff --git a/fs/glob_test.ts b/fs/glob_test.ts index 2dc509deee..fc3704ae3d 100644 --- a/fs/glob_test.ts +++ b/fs/glob_test.ts @@ -14,16 +14,16 @@ async function touch(path: string): Promise { async function walkArray( dirname: string = ".", options: WalkOptions = {} -): Promise> { +): Promise { const arr: string[] = []; for await (const f of walk(dirname, { ...options })) { arr.push(f.path.replace(/\\/g, "/")); } arr.sort(); - const arr_sync = Array.from(walkSync(dirname, options), (f: FileInfo) => + const arrSync = Array.from(walkSync(dirname, options), (f: FileInfo) => f.path.replace(/\\/g, "/") ).sort(); - assertEquals(arr, arr_sync); + assertEquals(arr, arrSync); return arr; } diff --git a/fs/globrex.ts b/fs/globrex.ts index 7f05146bdd..c3cf7a3372 100644 --- a/fs/globrex.ts +++ b/fs/globrex.ts @@ -12,6 +12,15 @@ const WILDCARD = `([^/]*)`; const GLOBSTAR_SEGMENT = `((?:[^${SEP_ESC}]*(?:${SEP_ESC}|$))*)`; const WILDCARD_SEGMENT = `([^${SEP_ESC}]*)`; +export interface GlobrexResult { + regex: RegExp; + path?: { + regex: string | RegExp; + segments: RegExp[]; + globstar?: RegExp; + }; +} + /** * Convert any glob pattern to a JavaScript Regexp object * @param {String} glob Glob pattern to convert @@ -32,12 +41,12 @@ export function globrex( filepath = false, flags = "" }: GlobOptions = {} -) { +): GlobrexResult { let regex = ""; let segment = ""; let path: { regex: string | RegExp; - segments: Array; + segments: RegExp[]; globstar?: RegExp; } = { regex: "", segments: [] }; @@ -59,7 +68,7 @@ export function globrex( function add( str, options: AddOptions = { split: false, last: false, only: "" } - ) { + ): void { const { split, last, only } = options; if (only !== "path") regex += str; if (filepath && only !== "regex") { @@ -283,14 +292,7 @@ export function globrex( if (filepath) path.regex = `^${path.regex}$`; } - const result: { - regex: RegExp; - path?: { - regex: string | RegExp; - segments: Array; - globstar?: RegExp; - }; - } = { regex: new RegExp(regex, flags) }; + const result: GlobrexResult = { regex: new RegExp(regex, flags) }; // Push the last segment if (filepath) { diff --git a/fs/globrex_test.ts b/fs/globrex_test.ts index df36dc5509..8d43b53521 100644 --- a/fs/globrex_test.ts +++ b/fs/globrex_test.ts @@ -4,12 +4,12 @@ import { test } from "../testing/mod.ts"; import { assertEquals } from "../testing/asserts.ts"; -import { globrex } from "./globrex.ts"; +import { globrex, GlobrexResult } from "./globrex.ts"; const isWin = Deno.build.os === "win"; const t = { equal: assertEquals, is: assertEquals }; -function match(glob, strUnix, strWin?, opts = {}) { +function match(glob, strUnix, strWin?, opts = {}): boolean { if (typeof strWin === "object") { opts = strWin; strWin = false; @@ -18,14 +18,14 @@ function match(glob, strUnix, strWin?, opts = {}) { return res.regex.test(isWin && strWin ? strWin : strUnix); } -function matchRegex(t, pattern, ifUnix, ifWin, opts) { +function matchRegex(t, pattern, ifUnix, ifWin, opts): GlobrexResult { const res = globrex(pattern, opts); const { regex } = opts.filepath ? res.path : res; t.is(regex.toString(), isWin ? ifWin : ifUnix, "~> regex matches expectant"); return res; } -function matchSegments(t, pattern, ifUnix, ifWin, opts) { +function matchSegments(t, pattern, ifUnix, ifWin, opts): GlobrexResult { const res = globrex(pattern, { filepath: true, ...opts }); const str = res.path.segments.join(" "); const exp = (isWin ? ifWin : ifUnix).join(" "); @@ -191,7 +191,7 @@ test({ t.equal(match("f?o", "fooo", { extended: true }), false); t.equal(match("f?oo", "foo", { extended: true }), false); - const tester = globstar => { + const tester = (globstar): void => { t.equal( match("f?o", "foo", { extended: true, globstar, flags: "g" }), true @@ -235,7 +235,7 @@ test({ t.equal(match("fo[!tz]", "fot", { extended: true }), false); t.equal(match("fo[!tz]", "fob", { extended: true }), true); - const tester = globstar => { + const tester = (globstar): void => { t.equal( match("fo[oz]", "foo", { extended: true, globstar, flags: "g" }), true @@ -321,7 +321,7 @@ test({ t.equal(match("foo{bar,baaz}", "foobuzz", { extended: true }), false); t.equal(match("foo{bar,b*z}", "foobuzz", { extended: true }), true); - const tester = globstar => { + const tester = (globstar): void => { t.equal( match("foo{bar,baaz}", "foobaaz", { extended: true, @@ -405,7 +405,7 @@ test({ false ); - const tester = globstar => { + const tester = (globstar): void => { t.equal( match( "http://?o[oz].b*z.com/{*.js,*.html}", @@ -456,7 +456,7 @@ test({ test({ name: "globrex: standard globstar", fn() { - const tester = globstar => { + const tester = (globstar): void => { t.equal( match( "http://foo.com/**/{*.js,*.html}", @@ -491,7 +491,7 @@ test({ test({ name: "globrex: remaining chars should match themself", fn() { - const tester = globstar => { + const tester = (globstar): void => { const testExtStr = "\\/$^+.()=!|,.*"; t.equal(match(testExtStr, testExtStr, { extended: true }), true); t.equal( @@ -849,7 +849,6 @@ test({ name: "globrex: filepath path segments", fn() { let opts = { extended: true }, - res, win, unix; diff --git a/fs/path/mod.ts b/fs/path/mod.ts index 4ca630ed6d..ffcc721a94 100644 --- a/fs/path/mod.ts +++ b/fs/path/mod.ts @@ -847,7 +847,7 @@ export const win32 = { parse(path: string): ParsedPath { assertPath(path); - let ret = { root: "", dir: "", base: "", ext: "", name: "" } as ParsedPath; + let ret: ParsedPath = { root: "", dir: "", base: "", ext: "", name: "" }; const len = path.length; if (len === 0) return ret; @@ -1324,7 +1324,7 @@ export const posix = { parse(path: string): ParsedPath { assertPath(path); - let ret = { root: "", dir: "", base: "", ext: "", name: "" } as ParsedPath; + let ret: ParsedPath = { root: "", dir: "", base: "", ext: "", name: "" }; if (path.length === 0) return ret; let isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; let start: number; diff --git a/fs/path/parse_format_test.ts b/fs/path/parse_format_test.ts index 29d8404530..05327a1395 100644 --- a/fs/path/parse_format_test.ts +++ b/fs/path/parse_format_test.ts @@ -79,6 +79,39 @@ const unixSpecialCaseFormatTests = [ [{}, ""] ]; +function checkParseFormat(path, paths): void { + paths.forEach(function(p) { + const element = p[0]; + const output = path.parse(element); + assertEquals(typeof output.root, "string"); + assertEquals(typeof output.dir, "string"); + assertEquals(typeof output.base, "string"); + assertEquals(typeof output.ext, "string"); + assertEquals(typeof output.name, "string"); + assertEquals(path.format(output), element); + assertEquals(output.rooroot, undefined); + assertEquals(output.dir, output.dir ? path.dirname(element) : ""); + assertEquals(output.base, path.basename(element)); + }); +} + +function checkSpecialCaseParseFormat(path, testCases): void { + testCases.forEach(function(testCase) { + const element = testCase[0]; + const expect = testCase[1]; + const output = path.parse(element); + Object.keys(expect).forEach(function(key) { + assertEquals(output[key], expect[key]); + }); + }); +} + +function checkFormat(path, testCases): void { + testCases.forEach(function(testCase) { + assertEquals(path.format(testCase[0]), testCase[1]); + }); +} + test(function parseWin32() { checkParseFormat(path.win32, winPaths); checkSpecialCaseParseFormat(path.win32, winSpecialCaseParseTests); @@ -116,6 +149,7 @@ const windowsTrailingTests = [ } ] ]; + const posixTrailingTests = [ ["./", { root: "", dir: "", base: ".", ext: "", name: "." }], ["//", { root: "/", dir: "/", base: "", ext: "", name: "" }], @@ -127,39 +161,6 @@ const posixTrailingTests = [ ] ]; -function checkParseFormat(path, paths) { - paths.forEach(function(p) { - const element = p[0]; - const output = path.parse(element); - assertEquals(typeof output.root, "string"); - assertEquals(typeof output.dir, "string"); - assertEquals(typeof output.base, "string"); - assertEquals(typeof output.ext, "string"); - assertEquals(typeof output.name, "string"); - assertEquals(path.format(output), element); - assertEquals(output.rooroot, undefined); - assertEquals(output.dir, output.dir ? path.dirname(element) : ""); - assertEquals(output.base, path.basename(element)); - }); -} - -function checkSpecialCaseParseFormat(path, testCases) { - testCases.forEach(function(testCase) { - const element = testCase[0]; - const expect = testCase[1]; - const output = path.parse(element); - Object.keys(expect).forEach(function(key) { - assertEquals(output[key], expect[key]); - }); - }); -} - -function checkFormat(path, testCases) { - testCases.forEach(function(testCase) { - assertEquals(path.format(testCase[0]), testCase[1]); - }); -} - test(function parseTrailingWin32() { windowsTrailingTests.forEach(function(p) { const actual = path.win32.parse(p[0] as string); diff --git a/fs/walk.ts b/fs/walk.ts index 24c800e59f..1e433e18b1 100644 --- a/fs/walk.ts +++ b/fs/walk.ts @@ -6,9 +6,52 @@ export interface WalkOptions { exts?: string[]; match?: RegExp[]; skip?: RegExp[]; - // FIXME don't use `any` here? - onError?: (err: any) => void; - followSymlinks?: Boolean; + onError?: (err: Error) => void; + followSymlinks?: boolean; +} + +function patternTest(patterns: RegExp[], path: string): boolean { + // Forced to reset last index on regex while iterating for have + // consistent results. + // See: https://stackoverflow.com/a/1520853 + return patterns.some(pattern => { + let r = pattern.test(path); + pattern.lastIndex = 0; + return r; + }); +} + +function include(f: FileInfo, options: WalkOptions): boolean { + if (options.exts && !options.exts.some(ext => f.path.endsWith(ext))) { + return false; + } + if (options.match && !patternTest(options.match, f.path)) { + return false; + } + if (options.skip && patternTest(options.skip, f.path)) { + return false; + } + return true; +} + +async function resolve(f: FileInfo): Promise { + // This is the full path, unfortunately if we were to make it relative + // it could resolve to a symlink and cause an infinite loop. + const fpath = await readlink(f.path); + f = await stat(fpath); + // workaround path not being returned by stat + f.path = fpath; + return f; +} + +function resolveSync(f: FileInfo): FileInfo { + // This is the full path, unfortunately if we were to make it relative + // it could resolve to a symlink and cause an infinite loop. + const fpath = readlinkSync(f.path); + f = statSync(fpath); + // workaround path not being returned by stat + f.path = fpath; + return f; } /** Generate all files in a directory recursively. @@ -94,47 +137,3 @@ export function* walkSync( } } } - -function include(f: FileInfo, options: WalkOptions): Boolean { - if (options.exts && !options.exts.some(ext => f.path.endsWith(ext))) { - return false; - } - if (options.match && !patternTest(options.match, f.path)) { - return false; - } - if (options.skip && patternTest(options.skip, f.path)) { - return false; - } - return true; -} - -function patternTest(patterns: RegExp[], path: string) { - // Forced to reset last index on regex while iterating for have - // consistent results. - // See: https://stackoverflow.com/a/1520853 - return patterns.some(pattern => { - let r = pattern.test(path); - pattern.lastIndex = 0; - return r; - }); -} - -async function resolve(f: FileInfo): Promise { - // This is the full path, unfortunately if we were to make it relative - // it could resolve to a symlink and cause an infinite loop. - const fpath = await readlink(f.path); - f = await stat(fpath); - // workaround path not being returned by stat - f.path = fpath; - return f; -} - -function resolveSync(f: FileInfo): FileInfo { - // This is the full path, unfortunately if we were to make it relative - // it could resolve to a symlink and cause an infinite loop. - const fpath = readlinkSync(f.path); - f = statSync(fpath); - // workaround path not being returned by stat - f.path = fpath; - return f; -} diff --git a/fs/walk_test.ts b/fs/walk_test.ts index 93073c6207..4c72de2c7d 100644 --- a/fs/walk_test.ts +++ b/fs/walk_test.ts @@ -11,15 +11,15 @@ export async function testWalk( t: TestFunction ): Promise { const name = t.name; - async function fn() { - const orig_cwd = cwd(); + async function fn(): Promise { + const origCwd = cwd(); const d = await makeTempDir(); chdir(d); try { await setup(d); await t(); } finally { - chdir(orig_cwd); + chdir(origCwd); remove(d, { recursive: true }); } } @@ -29,23 +29,23 @@ export async function testWalk( async function walkArray( dirname: string = ".", options: WalkOptions = {} -): Promise> { +): Promise { const arr: string[] = []; for await (const f of walk(dirname, { ...options })) { arr.push(f.path.replace(/\\/g, "/")); } arr.sort(); - const arr_sync = Array.from(walkSync(dirname, options), (f: FileInfo) => + const arrSync = Array.from(walkSync(dirname, options), (f: FileInfo) => f.path.replace(/\\/g, "/") ).sort(); - assertEquals(arr, arr_sync); + assertEquals(arr, arrSync); return arr; } async function touch(path: string): Promise { await open(path, "w"); } -function assertReady(expectedLength: number) { +function assertReady(expectedLength: number): void { const arr = Array.from(walkSync(), (f: FileInfo) => f.path); assertEquals(arr.length, expectedLength); } @@ -77,11 +77,11 @@ testWalk( }, async function iteratable() { let count = 0; - for (const f of walkSync()) { + for (const _ of walkSync()) { count += 1; } assertEquals(count, 1); - for await (const f of walk()) { + for await (const _ of walk()) { count += 1; } assertEquals(count, 2); @@ -107,11 +107,11 @@ testWalk( }, async function depth() { assertReady(1); - const arr_3 = await walkArray(".", { maxDepth: 3 }); - assertEquals(arr_3.length, 0); - const arr_5 = await walkArray(".", { maxDepth: 5 }); - assertEquals(arr_5.length, 1); - assertEquals(arr_5[0], "./a/b/c/d/x"); + const arr3 = await walkArray(".", { maxDepth: 3 }); + assertEquals(arr3.length, 0); + const arr5 = await walkArray(".", { maxDepth: 5 }); + assertEquals(arr5.length, 1); + assertEquals(arr5[0], "./a/b/c/d/x"); } ); @@ -214,12 +214,12 @@ testWalk( } ); -testWalk(async (d: string) => {}, async function onError() { +testWalk(async (_d: string) => {}, async function onError() { assertReady(0); const ignored = await walkArray("missing"); assertEquals(ignored.length, 0); let errors = 0; - const arr = await walkArray("missing", { onError: e => (errors += 1) }); + await walkArray("missing", { onError: _e => (errors += 1) }); // It's 2 since walkArray iterates over both sync and async. assertEquals(errors, 2); }); diff --git a/http/file_server.ts b/http/file_server.ts index 659e9ba562..83de373648 100755 --- a/http/file_server.ts +++ b/http/file_server.ts @@ -188,7 +188,7 @@ async function serveDir( async function serveFallback(req: ServerRequest, e: Error): Promise { if ( e instanceof Deno.DenoError && - (e as Deno.DenoError).kind === ErrorKind.NotFound + (e as Deno.DenoError).kind === ErrorKind.NotFound ) { return { status: 404, diff --git a/http/file_server_test.ts b/http/file_server_test.ts index 15f052e6e8..31ddca08eb 100644 --- a/http/file_server_test.ts +++ b/http/file_server_test.ts @@ -7,7 +7,7 @@ import { BufReader } from "../io/bufio.ts"; import { TextProtoReader } from "../textproto/mod.ts"; let fileServer; -async function startFileServer() { +async function startFileServer(): Promise { fileServer = run({ args: [ "deno", @@ -25,7 +25,7 @@ async function startFileServer() { assert(err == null); assert(s.includes("server listening")); } -function killFileServer() { +function killFileServer(): void { fileServer.close(); fileServer.stdout.close(); } diff --git a/http/server.ts b/http/server.ts index 5cf658cf34..17295f7399 100644 --- a/http/server.ts +++ b/http/server.ts @@ -36,7 +36,7 @@ export function setContentLength(r: Response): void { } } } -async function writeChunkedBody(w: Writer, r: Reader) { +async function writeChunkedBody(w: Writer, r: Reader): Promise { const writer = bufWriter(w); const encoder = new TextEncoder(); @@ -123,7 +123,7 @@ export class ServerRequest { r: BufReader; w: BufWriter; - public async *bodyStream() { + public async *bodyStream(): AsyncIterableIterator { if (this.headers.has("content-length")) { const len = +this.headers.get("content-length"); if (Number.isNaN(len)) { @@ -263,7 +263,11 @@ async function readRequest( return [req, err]; } -function maybeHandleReq(env: ServeEnv, conn: Conn, maybeReq: any) { +function maybeHandleReq( + env: ServeEnv, + conn: Conn, + maybeReq: [ServerRequest, BufState] +): void { const [req, _err] = maybeReq; if (_err) { conn.close(); // assume EOF for now... @@ -273,11 +277,13 @@ function maybeHandleReq(env: ServeEnv, conn: Conn, maybeReq: any) { env.serveDeferred.resolve(); // signal while loop to process it } -function serveConn(env: ServeEnv, conn: Conn, bufr?: BufReader) { +function serveConn(env: ServeEnv, conn: Conn, bufr?: BufReader): void { readRequest(conn, bufr).then(maybeHandleReq.bind(null, env, conn)); } -export async function* serve(addr: string) { +export async function* serve( + addr: string +): AsyncIterableIterator { const listener = listen("tcp", addr); const env: ServeEnv = { reqQueue: [], // in case multiple promises are ready @@ -285,9 +291,9 @@ export async function* serve(addr: string) { }; // Routine that keeps calling accept - let handleConn = (_conn: Conn) => {}; - let scheduleAccept = () => {}; - const acceptRoutine = () => { + let handleConn = (_conn: Conn): void => {}; + let scheduleAccept = (): void => {}; + const acceptRoutine = (): void => { scheduleAccept = () => { listener.accept().then(handleConn); }; @@ -320,7 +326,7 @@ export async function* serve(addr: string) { export async function listenAndServe( addr: string, handler: (req: ServerRequest) => void -) { +): Promise { const server = serve(addr); for await (const request of server) { diff --git a/testing/asserts.ts b/testing/asserts.ts index 33d6073eaf..6d975bbb59 100644 --- a/testing/asserts.ts +++ b/testing/asserts.ts @@ -161,7 +161,7 @@ export function assertArrayContains( actual: unknown[], expected: unknown[], msg?: string -) { +): void { let missing = []; for (let i = 0; i < expected.length; i++) { let found = false; diff --git a/ws/mod.ts b/ws/mod.ts index b68f3ad4a6..65dc142ca9 100644 --- a/ws/mod.ts +++ b/ws/mod.ts @@ -23,10 +23,10 @@ export type WebSocketEvent = | WebSocketPingEvent | WebSocketPongEvent; -export type WebSocketCloseEvent = { +export interface WebSocketCloseEvent { code: number; reason?: string; -}; +} export function isWebSocketCloseEvent(a): a is WebSocketCloseEvent { return a && typeof a["code"] === "number"; @@ -47,7 +47,7 @@ export function isWebSocketPongEvent(a): a is WebSocketPongEvent { export type WebSocketMessage = string | Uint8Array; // TODO move this to common/util module -export function append(a: Uint8Array, b: Uint8Array) { +export function append(a: Uint8Array, b: Uint8Array): Uint8Array { if (a == null || !a.length) { return b; } @@ -62,20 +62,145 @@ export function append(a: Uint8Array, b: Uint8Array) { export class SocketClosedError extends Error {} -export type WebSocketFrame = { +export interface WebSocketFrame { isLastFrame: boolean; opcode: OpCode; mask?: Uint8Array; payload: Uint8Array; -}; +} -export type WebSocket = { +export interface WebSocket { readonly isClosed: boolean; receive(): AsyncIterableIterator; send(data: WebSocketMessage): Promise; ping(data?: WebSocketMessage): Promise; close(code: number, reason?: string): Promise; -}; +} + +export function unmask(payload: Uint8Array, mask?: Uint8Array): void { + if (mask) { + for (let i = 0, len = payload.length; i < len; i++) { + payload[i] ^= mask![i & 3]; + } + } +} + +export async function writeFrame( + frame: WebSocketFrame, + writer: Writer +): Promise { + const payloadLength = frame.payload.byteLength; + let header: Uint8Array; + const hasMask = frame.mask ? 0x80 : 0; + if (payloadLength < 126) { + header = new Uint8Array([0x80 | frame.opcode, hasMask | payloadLength]); + } else if (payloadLength < 0xffff) { + header = new Uint8Array([ + 0x80 | frame.opcode, + hasMask | 0b01111110, + payloadLength >>> 8, + payloadLength & 0x00ff + ]); + } else { + header = new Uint8Array([ + 0x80 | frame.opcode, + hasMask | 0b01111111, + ...sliceLongToBytes(payloadLength) + ]); + } + unmask(frame.payload, frame.mask); + const bytes = append(header, frame.payload); + const w = new BufWriter(writer); + await w.write(bytes); + await w.flush(); +} + +export async function readFrame(buf: BufReader): Promise { + let b = await buf.readByte(); + let isLastFrame = false; + switch (b >>> 4) { + case 0b1000: + isLastFrame = true; + break; + case 0b0000: + isLastFrame = false; + break; + default: + throw new Error("invalid signature"); + } + const opcode = b & 0x0f; + // has_mask & payload + b = await buf.readByte(); + const hasMask = b >>> 7; + let payloadLength = b & 0b01111111; + if (payloadLength === 126) { + payloadLength = await readShort(buf); + } else if (payloadLength === 127) { + payloadLength = await readLong(buf); + } + // mask + let mask; + if (hasMask) { + mask = new Uint8Array(4); + await buf.readFull(mask); + } + // payload + const payload = new Uint8Array(payloadLength); + await buf.readFull(payload); + return { + isLastFrame, + opcode, + mask, + payload + }; +} + +export async function* receiveFrame( + conn: Conn +): AsyncIterableIterator { + let receiving = true; + const isLastFrame = true; + const reader = new BufReader(conn); + while (receiving) { + const frame = await readFrame(reader); + const { opcode, payload } = frame; + switch (opcode) { + case OpCode.TextFrame: + case OpCode.BinaryFrame: + case OpCode.Continue: + yield frame; + break; + case OpCode.Close: + await writeFrame( + { + opcode, + payload, + isLastFrame + }, + conn + ); + conn.close(); + yield frame; + receiving = false; + break; + case OpCode.Ping: + await writeFrame( + { + payload, + isLastFrame, + opcode: OpCode.Pong + }, + conn + ); + yield frame; + break; + case OpCode.Pong: + yield frame; + break; + default: + } + } +} class WebSocketImpl implements WebSocket { encoder = new TextEncoder(); @@ -163,7 +288,7 @@ class WebSocketImpl implements WebSocket { } private _isClosed = false; - get isClosed() { + get isClosed(): boolean { return this._isClosed; } @@ -210,88 +335,6 @@ class WebSocketImpl implements WebSocket { } } -export async function* receiveFrame( - conn: Conn -): AsyncIterableIterator { - let receiving = true; - const isLastFrame = true; - const reader = new BufReader(conn); - while (receiving) { - const frame = await readFrame(reader); - const { opcode, payload } = frame; - switch (opcode) { - case OpCode.TextFrame: - case OpCode.BinaryFrame: - case OpCode.Continue: - yield frame; - break; - case OpCode.Close: - await writeFrame( - { - opcode, - payload, - isLastFrame - }, - conn - ); - conn.close(); - yield frame; - receiving = false; - break; - case OpCode.Ping: - await writeFrame( - { - payload, - isLastFrame, - opcode: OpCode.Pong - }, - conn - ); - yield frame; - break; - case OpCode.Pong: - yield frame; - break; - default: - } - } -} - -export async function writeFrame(frame: WebSocketFrame, writer: Writer) { - const payloadLength = frame.payload.byteLength; - let header: Uint8Array; - const hasMask = frame.mask ? 0x80 : 0; - if (payloadLength < 126) { - header = new Uint8Array([0x80 | frame.opcode, hasMask | payloadLength]); - } else if (payloadLength < 0xffff) { - header = new Uint8Array([ - 0x80 | frame.opcode, - hasMask | 0b01111110, - payloadLength >>> 8, - payloadLength & 0x00ff - ]); - } else { - header = new Uint8Array([ - 0x80 | frame.opcode, - hasMask | 0b01111111, - ...sliceLongToBytes(payloadLength) - ]); - } - unmask(frame.payload, frame.mask); - const bytes = append(header, frame.payload); - const w = new BufWriter(writer); - await w.write(bytes); - await w.flush(); -} - -export function unmask(payload: Uint8Array, mask?: Uint8Array) { - if (mask) { - for (let i = 0, len = payload.length; i < len; i++) { - payload[i] ^= mask![i & 3]; - } - } -} - export function acceptable(req: { headers: Headers }): boolean { return ( req.headers.get("upgrade") === "websocket" && @@ -300,6 +343,15 @@ export function acceptable(req: { headers: Headers }): boolean { ); } +const kGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + +export function createSecAccept(nonce: string): string { + const sha1 = new Sha1(); + sha1.update(nonce + kGUID); + const bytes = sha1.digest(); + return btoa(String.fromCharCode.apply(String, bytes)); +} + export async function acceptWebSocket(req: { conn: Conn; headers: Headers; @@ -321,52 +373,3 @@ export async function acceptWebSocket(req: { } throw new Error("request is not acceptable"); } - -const kGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - -export function createSecAccept(nonce: string) { - const sha1 = new Sha1(); - sha1.update(nonce + kGUID); - const bytes = sha1.digest(); - return btoa(String.fromCharCode.apply(String, bytes)); -} - -export async function readFrame(buf: BufReader): Promise { - let b = await buf.readByte(); - let isLastFrame = false; - switch (b >>> 4) { - case 0b1000: - isLastFrame = true; - break; - case 0b0000: - isLastFrame = false; - break; - default: - throw new Error("invalid signature"); - } - const opcode = b & 0x0f; - // has_mask & payload - b = await buf.readByte(); - const hasMask = b >>> 7; - let payloadLength = b & 0b01111111; - if (payloadLength === 126) { - payloadLength = await readShort(buf); - } else if (payloadLength === 127) { - payloadLength = await readLong(buf); - } - // mask - let mask; - if (hasMask) { - mask = new Uint8Array(4); - await buf.readFull(mask); - } - // payload - const payload = new Uint8Array(payloadLength); - await buf.readFull(payload); - return { - isLastFrame, - opcode, - mask, - payload - }; -} diff --git a/ws/sha1.ts b/ws/sha1.ts index c30a1e6ac9..d01df21adf 100644 --- a/ws/sha1.ts +++ b/ws/sha1.ts @@ -47,7 +47,7 @@ export class Sha1 { this._finalized = this._hashed = false; } - update(data: string | ArrayBuffer | ArrayBufferView) { + update(data: string | ArrayBuffer | ArrayBufferView): void { if (this._finalized) { return; } @@ -120,7 +120,7 @@ export class Sha1 { } } - finalize() { + finalize(): void { if (this._finalized) { return; } @@ -142,7 +142,7 @@ export class Sha1 { this.hash(); } - hash() { + hash(): void { let a = this._h0; let b = this._h1; let c = this._h2; @@ -271,7 +271,7 @@ export class Sha1 { this._h4 = (this._h4 + e) >>> 0; } - hex() { + hex(): string { this.finalize(); const h0 = this._h0; @@ -324,11 +324,11 @@ export class Sha1 { ); } - toString() { + toString(): string { return this.hex(); } - digest() { + digest(): number[] { this.finalize(); const h0 = this._h0; @@ -361,11 +361,11 @@ export class Sha1 { ]; } - array() { + array(): number[] { return this.digest(); } - arrayBuffer() { + arrayBuffer(): ArrayBuffer { this.finalize(); return Uint32Array.of(this._h0, this._h1, this._h2, this._h3, this._h4) .buffer;