1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-22 15:06:54 -05:00

chore: Implement strict mode (denoland/deno_std#453)

Original: be24677d15
This commit is contained in:
Bartek Iwańczuk 2019-05-30 14:59:30 +02:00 committed by Ryan Dahl
parent 80b3c486f6
commit 50a79584cb
51 changed files with 466 additions and 371 deletions

View file

@ -35,8 +35,10 @@ const ustar = "ustar\u000000";
* Simple file reader
*/
export class FileReader implements Deno.Reader {
private file: Deno.File;
private file?: Deno.File;
constructor(private filePath: string, private mode: Deno.OpenMode = "r") {}
public async read(p: Uint8Array): Promise<Deno.ReadResult> {
if (!this.file) {
this.file = await Deno.open(this.filePath, this.mode);
@ -44,7 +46,7 @@ export class FileReader implements Deno.Reader {
const res = await Deno.read(this.file.rid, p);
if (res.eof) {
await Deno.close(this.file.rid);
this.file = null;
this.file = undefined;
}
return res;
}
@ -54,18 +56,21 @@ export class FileReader implements Deno.Reader {
* Simple file writer (call FileWriter.dispose() after use)
*/
export class FileWriter implements Deno.Writer {
private file: Deno.File;
private file?: Deno.File;
constructor(private filePath: string, private mode: Deno.OpenMode = "w") {}
public async write(p: Uint8Array): Promise<number> {
if (!this.file) {
this.file = await Deno.open(this.filePath, this.mode);
}
return Deno.write(this.file.rid, p);
}
public dispose(): void {
if (!this.file) return;
Deno.close(this.file.rid);
this.file = null;
this.file = undefined;
}
}
@ -191,7 +196,7 @@ function formatHeader(data: TarData): Uint8Array {
buffer = clean(512);
let offset = 0;
ustarStructure.forEach(function(value): void {
const entry = encoder.encode(data[value.field] || "");
const entry = encoder.encode(data[value.field as keyof TarData] || "");
buffer.set(entry, offset);
offset += value.length; // space it out with nulls
});
@ -307,12 +312,13 @@ export class Tar {
}
i--;
}
if (i < 0 || fileName.length > 100 || fileNamePrefix.length > 155) {
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)"
);
}
}
fileNamePrefix = fileNamePrefix!;
opts = opts || {};
@ -344,7 +350,7 @@ export class Tar {
fileMode: pad(mode, 7),
uid: pad(uid, 7),
gid: pad(gid, 7),
fileSize: pad(info ? info.len : opts.contentSize, 11),
fileSize: pad((info ? info.len : opts.contentSize)!, 11),
mtime: pad(mtime, 11),
checksum: " ",
type: "0", // just a file
@ -362,7 +368,7 @@ export class Tar {
.filter((key): boolean => ["filePath", "reader"].indexOf(key) < 0)
.forEach(function(key): void {
checksum += encoder
.encode(tarData[key])
.encode(tarData[key as keyof TarData])
.reduce((p, c): number => p + c, 0);
});
@ -381,7 +387,7 @@ export class Tar {
headerArr = formatHeader(tarData);
readers.push(new Deno.Buffer(headerArr));
if (!reader) {
reader = new FileReader(filePath);
reader = new FileReader(filePath!);
}
readers.push(reader);
@ -390,7 +396,7 @@ export class Tar {
new Deno.Buffer(
clean(
recordSize -
(parseInt(tarData.fileSize, 8) % recordSize || recordSize)
(parseInt(tarData.fileSize!, 8) % recordSize || recordSize)
)
)
);
@ -451,7 +457,7 @@ export class Untar {
(key): void => {
const arr = trim(header[key]);
if (arr.byteLength > 0) {
meta[key] = parseInt(decoder.decode(arr), 8);
meta[key as keyof UntarOptions] = parseInt(decoder.decode(arr), 8);
}
}
);
@ -459,7 +465,7 @@ export class Untar {
(key): void => {
const arr = trim(header[key]);
if (arr.byteLength > 0) {
meta[key] = decoder.decode(arr);
meta[key as keyof UntarOptions] = decoder.decode(arr);
}
}
);

View file

@ -14,7 +14,7 @@ jobs:
- script: echo '##vso[task.prependpath]$(HOME)/.deno/bin/'
- script: npx eslint **/*.ts --max-warnings=0
- script: deno run --allow-run --allow-write --allow-read format.ts --check
- script: deno run --allow-run --allow-net --allow-write --allow-read test.ts
- script: deno run --allow-run --allow-net --allow-write --allow-read --config=tsconfig.test.json test.ts
- job: "Mac"
pool:
@ -26,7 +26,7 @@ jobs:
- script: echo '##vso[task.prependpath]$(HOME)/.deno/bin/'
- script: eslint **/*.ts --max-warnings=0
- script: deno run --allow-run --allow-write --allow-read format.ts --check
- script: deno run --allow-run --allow-net --allow-write --allow-read test.ts
- script: deno run --allow-run --allow-net --allow-write --allow-read --config=tsconfig.test.json test.ts
- job: "Windows"
pool:
@ -37,4 +37,4 @@ jobs:
- bash: echo "##vso[task.prependpath]C:\Users\VssAdministrator\.deno\\bin"
- bash: npx eslint **/*.ts --max-warnings=0
- bash: deno.exe run --allow-run --allow-write --allow-read format.ts --check
- bash: deno.exe run --allow-run --allow-net --allow-write --allow-read test.ts
- bash: deno.exe run --allow-run --allow-net --allow-write --allow-read --config=tsconfig.test.json test.ts

View file

@ -28,7 +28,7 @@ export interface ParseOptions {
function chkOptions(opt: ParseOptions): void {
if (
INVALID_RUNE.includes(opt.comma) ||
INVALID_RUNE.includes(opt.comment) ||
(opt.comment && INVALID_RUNE.includes(opt.comment)) ||
opt.comma === opt.comment
) {
throw new Error("Invalid Delimiter");
@ -130,7 +130,7 @@ export async function readAll(
}
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);

View file

@ -441,7 +441,7 @@ for (const t of testCases) {
if (t.Error) {
let err;
try {
actual = await readAll(new BufReader(new StringReader(t.Input)), {
actual = await readAll(new BufReader(new StringReader(t.Input!)), {
comma: comma,
comment: comment,
trimLeadingSpace: trim,
@ -454,7 +454,7 @@ for (const t of testCases) {
assert(err);
assertEquals(err.message, t.Error);
} else {
actual = await readAll(new BufReader(new StringReader(t.Input)), {
actual = await readAll(new BufReader(new StringReader(t.Input!)), {
comma: comma,
comment: comment,
trimLeadingSpace: trim,

View file

@ -3,20 +3,19 @@ import { deepAssign } from "../util/deep_assign.ts";
import { pad } from "../strings/pad.ts";
class KeyValuePair {
key: string;
value: unknown;
constructor(public key: string, public value: unknown) {}
}
class ParserGroup {
type: string;
name: string;
arrValues: unknown[] = [];
objValues: object = {};
objValues: Record<string, unknown> = {};
constructor(public type: string, public name: string) {}
}
class ParserContext {
currentGroup?: ParserGroup;
output: object = {};
output: Record<string, unknown> = {};
}
class Parser {
@ -27,7 +26,7 @@ class Parser {
this.context = new ParserContext();
}
_sanitize(): void {
const out = [];
const out: string[] = [];
for (let i = 0; i < this.tomlLines.length; i++) {
const s = this.tomlLines[i];
const trimmed = s.trim();
@ -124,28 +123,30 @@ class Parser {
this.tomlLines = merged;
}
_unflat(keys: string[], values: object = {}, cObj: object = {}): object {
let out = {};
let out: Record<string, unknown> = {};
if (keys.length === 0) {
return cObj;
} else {
if (Object.keys(cObj).length === 0) {
cObj = values;
}
let key = keys.pop();
out[key] = cObj;
let key: string | undefined = keys.pop();
if (key) {
out[key] = cObj;
}
return this._unflat(keys, values, out);
}
}
_groupToOutput(): void {
const arrProperty = this.context.currentGroup.name
.replace(/"/g, "")
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;
@ -167,22 +168,22 @@ class Parser {
if (this.context.currentGroup) {
this._groupToOutput();
}
let g = new ParserGroup();
g.name = line.match(captureReg)[1];
if (g.name.match(/\[.*\]/)) {
g.type = "array";
g.name = g.name.match(captureReg)[1];
let type;
let name = line.match(captureReg)![1];
if (name.match(/\[.*\]/)) {
type = "array";
name = name.match(captureReg)![1];
} else {
g.type = "object";
type = "object";
}
this.context.currentGroup = g;
this.context.currentGroup = new ParserGroup(type, name);
}
_processDeclaration(line: string): KeyValuePair {
let kv = new KeyValuePair();
const idx = line.indexOf("=");
kv.key = line.substring(0, idx).trim();
kv.value = this._parseData(line.slice(idx + 1));
return kv;
const key = line.substring(0, idx).trim();
const value = this._parseData(line.slice(idx + 1));
return new KeyValuePair(key, value);
}
// TODO (zekth) Need refactor using ACC
_parseData(dataString: string): unknown {
@ -353,23 +354,27 @@ class Parser {
_cleanOutput(): void {
this._propertyClean(this.context.output);
}
_propertyClean(obj: object): void {
_propertyClean(obj: Record<string, unknown>): void {
const keys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {
let k = keys[i];
let v = obj[k];
let pathDeclaration = this._parseDeclarationName(k);
delete obj[k];
if (pathDeclaration.length > 1) {
k = pathDeclaration.shift();
k = k.replace(/"/g, "");
v = this._unflat(pathDeclaration, v as object);
} else {
k = k.replace(/"/g, "");
}
obj[k] = v;
if (v instanceof Object) {
this._propertyClean(v);
if (k) {
let v = obj[k];
let pathDeclaration = this._parseDeclarationName(k);
delete obj[k];
if (pathDeclaration.length > 1) {
const shift = pathDeclaration.shift();
if (shift) {
k = shift.replace(/"/g, "");
v = this._unflat(pathDeclaration, v as object);
}
} else {
k = k.replace(/"/g, "");
}
obj[k] = v;
if (v instanceof Object) {
this._propertyClean(v);
}
}
}
}
@ -393,18 +398,26 @@ class Dumper {
this.output = this._format();
return this.output;
}
_parse(obj: object, path: string = ""): string[] {
_parse(obj: Record<string, unknown>, path: string = ""): string[] {
const out = [];
const props = Object.keys(obj);
const propObj = props.filter(
(e): boolean =>
(obj[e] instanceof Array && !this._isSimplySerializable(obj[e][0])) ||
!this._isSimplySerializable(obj[e])
(e: string): boolean => {
if (obj[e] instanceof Array) {
const d: unknown[] = obj[e] as unknown[];
return !this._isSimplySerializable(d[0]);
}
return !this._isSimplySerializable(obj[e]);
}
);
const propPrim = props.filter(
(e): boolean =>
!(obj[e] instanceof Array && !this._isSimplySerializable(obj[e][0])) &&
this._isSimplySerializable(obj[e])
(e: string): boolean => {
if (obj[e] instanceof Array) {
const d: unknown[] = obj[e] as unknown[];
return this._isSimplySerializable(d[0]);
}
return this._isSimplySerializable(obj[e]);
}
);
const k = propPrim.concat(propObj);
for (let i = 0; i < k.length; i++) {
@ -435,7 +448,11 @@ class Dumper {
} else if (typeof value === "object") {
out.push("");
out.push(this._header(path + prop));
out.push(...this._parse(value, `${path}${prop}.`));
if (value) {
const toParse: Record<string, unknown> = value;
out.push(...this._parse(toParse, `${path}${prop}.`));
}
// out.push(...this._parse(value, `${path}${prop}.`));
}
}
out.push("");

View file

@ -19,7 +19,7 @@ test(function flagBooleanTrue(): void {
// flag boolean true only affects double hyphen arguments without equals signs
test(function flagBooleanTrueOnlyAffectsDoubleDash(): void {
var argv = parse(["moo", "--honk", "cow", "-p", "55", "--tacos=good"], {
const argv = parse(["moo", "--honk", "cow", "-p", "55", "--tacos=good"], {
boolean: true
});

View file

@ -8,17 +8,18 @@ test(function dottedAlias(): void {
default: { "a.b": 11 },
alias: { "a.b": "aa.bb" }
});
console.log(argv.a);
assertEquals(argv.a.b, 22);
assertEquals(argv.aa.bb, 22);
});
test(function dottedDefault(): void {
const argv = parse("", { default: { "a.b": 11 }, alias: { "a.b": "aa.bb" } });
const argv = parse([], { default: { "a.b": 11 }, alias: { "a.b": "aa.bb" } });
assertEquals(argv.a.b, 11);
assertEquals(argv.aa.bb, 11);
});
test(function dottedDefaultWithNoAlias(): void {
const argv = parse("", { default: { "a.b": 11 } });
const argv = parse([], { default: { "a.b": 11 } });
assertEquals(argv.a.b, 11);
});

View file

@ -1,16 +1,16 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
export interface ArgParsingOptions {
unknown?: Function;
unknown?: (i: unknown) => unknown;
boolean?: boolean | string | string[];
alias?: { [key: string]: string | string[] };
string?: string | string[];
default?: { [key: string]: any }; // eslint-disable-line @typescript-eslint/no-explicit-any
default?: { [key: string]: unknown }; // eslint-disable-line @typescript-eslint/no-explicit-any
"--"?: boolean;
stopEarly?: boolean;
}
const DEFAULT_OPTIONS = {
unknown: (i): unknown => i,
unknown: (i: unknown): unknown => i,
boolean: false,
alias: {},
string: [],
@ -19,16 +19,27 @@ const DEFAULT_OPTIONS = {
stopEarly: false
};
interface Flags {
bools: { [key: string]: boolean };
strings: { [key: string]: boolean };
unknownFn: (i: unknown) => unknown;
allBools: boolean;
}
interface NestedMapping {
[key: string]: NestedMapping | unknown;
}
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 {
function hasKey(obj: NestedMapping, keys: string[]): boolean {
let o = obj;
keys.slice(0, -1).forEach(function(key): void {
o = o[key] || {};
keys.slice(0, -1).forEach(function(key: string): void {
o = (o[key] || {}) as NestedMapping;
});
const key = keys[keys.length - 1];
@ -36,7 +47,8 @@ function hasKey(obj, keys): boolean {
}
export function parse(
args,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
args: any[],
initialOptions?: ArgParsingOptions
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): { [key: string]: any } {
@ -45,65 +57,85 @@ export function parse(
...(initialOptions || {})
};
const flags = {
const flags: Flags = {
bools: {},
strings: {},
unknownFn: options.unknown!,
allBools: false
};
// TODO: get rid of this, providing two different options
if (typeof options["boolean"] === "boolean" && options["boolean"]) {
flags.allBools = true;
} else {
[]
.concat(options["boolean"])
.filter(Boolean)
.forEach(function(key): void {
flags.bools[key] = true;
});
if (options.boolean !== undefined) {
if (typeof options.boolean === "boolean") {
flags.allBools = !!options.boolean;
} else {
const booleanArgs: string[] =
typeof options.boolean === "string"
? [options.boolean]
: options.boolean;
booleanArgs.filter(Boolean).forEach(
(key: string): void => {
flags.bools[key] = true;
}
);
}
}
const aliases = {};
Object.keys(options.alias).forEach(function(key): void {
aliases[key] = [].concat(options.alias[key]);
aliases[key].forEach(function(x): void {
aliases[x] = [key].concat(
aliases[key].filter(function(y): boolean {
return x !== y;
})
);
});
});
const aliases: { [key: string]: string[] } = {};
if (options.alias !== undefined) {
for (const key in options.alias) {
const val = options.alias[key];
[]
.concat(options.string)
.filter(Boolean)
.forEach(function(key): void {
if (typeof val === "string") {
aliases[key] = [val];
} else {
aliases[key] = val;
}
for (const alias of aliases[key]) {
aliases[alias] = [key].concat(
aliases[key].filter((y: string): boolean => alias !== y)
);
}
}
}
if (options.string !== undefined) {
const stringArgs =
typeof options.string === "string" ? [options.string] : options.string;
stringArgs.filter(Boolean).forEach(function(key): void {
flags.strings[key] = true;
if (aliases[key]) {
flags.strings[aliases[key]] = true;
aliases[key].forEach(
(alias: string): void => {
flags.strings[alias] = true;
}
);
}
});
}
const defaults = options.default!;
const argv = { _: [] };
const argv: { [key: string]: unknown[] } = { _: [] };
function argDefined(key, arg): boolean {
function argDefined(key: string, arg: string): boolean {
return (
(flags.allBools && /^--[^=]+$/.test(arg)) ||
flags.strings[key] ||
flags.bools[key] ||
aliases[key]
!!flags.strings[key] ||
!!aliases[key]
);
}
function setKey(obj, keys, value): void {
function setKey(obj: NestedMapping, keys: string[], value: unknown): void {
let o = obj;
keys.slice(0, -1).forEach(function(key): void {
if (o[key] === undefined) o[key] = {};
o = o[key];
if (o[key] === undefined) {
o[key] = {};
}
o = o[key] as NestedMapping;
});
const key = keys[keys.length - 1];
@ -114,13 +146,17 @@ export function parse(
) {
o[key] = value;
} else if (Array.isArray(o[key])) {
o[key].push(value);
(o[key] as unknown[]).push(value);
} else {
o[key] = [o[key], value];
}
}
function setArg(key, val, arg = null): void {
function setArg(
key: string,
val: unknown,
arg: string | undefined = undefined
): void {
if (arg && flags.unknownFn && !argDefined(key, arg)) {
if (flags.unknownFn(arg) === false) return;
}
@ -133,7 +169,7 @@ export function parse(
});
}
function aliasIsBoolean(key): boolean {
function aliasIsBoolean(key: string): boolean {
return aliases[key].some(function(x): boolean {
return flags.bools[x];
});
@ -143,8 +179,9 @@ export function parse(
setArg(key, defaults[key] === undefined ? false : defaults[key]);
});
let notFlags = [];
let notFlags: string[] = [];
// all args after "--" are not parsed
if (args.indexOf("--") !== -1) {
notFlags = args.slice(args.indexOf("--") + 1);
args = args.slice(0, args.indexOf("--"));
@ -157,18 +194,21 @@ 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]*)$/)!;
const key = m[1];
let value = m[2];
const value = m[2];
if (flags.bools[key]) {
value = value !== "false";
const booleanValue = value !== "false";
setArg(key, booleanValue, arg);
} else {
setArg(key, value, arg);
}
setArg(key, value, arg);
} else if (/^--no-.+/.test(arg)) {
const key = arg.match(/^--no-(.+)/)[1];
const key = arg.match(/^--no-(.+)/)![1];
setArg(key, false, arg);
} else if (/^--.+/.test(arg)) {
const key = arg.match(/^--(.+)/)[1];
const key = arg.match(/^--(.+)/)![1];
const next = args[i + 1];
if (
next !== undefined &&

View file

@ -4,8 +4,8 @@ import { assertEquals } from "../testing/asserts.ts";
import { parse } from "./mod.ts";
test(function booleanAndAliasIsNotUnknown(): void {
const unknown = [];
function unknownFn(arg): boolean {
const unknown: unknown[] = [];
function unknownFn(arg: unknown): boolean {
unknown.push(arg);
return false;
}
@ -23,8 +23,8 @@ test(function booleanAndAliasIsNotUnknown(): void {
});
test(function flagBooleanTrueAnyDoubleHyphenArgumentIsNotUnknown(): void {
const unknown = [];
function unknownFn(arg): boolean {
const unknown: unknown[] = [];
function unknownFn(arg: unknown): boolean {
unknown.push(arg);
return false;
}
@ -40,8 +40,8 @@ test(function flagBooleanTrueAnyDoubleHyphenArgumentIsNotUnknown(): void {
});
test(function stringAndAliasIsNotUnkown(): void {
const unknown = [];
function unknownFn(arg): boolean {
const unknown: unknown[] = [];
function unknownFn(arg: unknown): boolean {
unknown.push(arg);
return false;
}
@ -59,8 +59,8 @@ test(function stringAndAliasIsNotUnkown(): void {
});
test(function defaultAndAliasIsNotUnknown(): void {
const unknown = [];
function unknownFn(arg): boolean {
const unknown: unknown[] = [];
function unknownFn(arg: unknown): boolean {
unknown.push(arg);
return false;
}
@ -78,8 +78,8 @@ test(function defaultAndAliasIsNotUnknown(): void {
});
test(function valueFollowingDoubleHyphenIsNotUnknown(): void {
const unknown = [];
function unknownFn(arg): boolean {
const unknown: unknown[] = [];
function unknownFn(arg: unknown): boolean {
unknown.push(arg);
return false;
}

View file

@ -22,7 +22,7 @@ async function ensureValidCopy(
options: CopyOptions,
isCopyFolder: boolean = false
): Promise<Deno.FileInfo> {
let destStat: Deno.FileInfo;
let destStat: Deno.FileInfo | null;
destStat = await Deno.lstat(dest).catch(
(): Promise<null> => Promise.resolve(null)
@ -39,7 +39,7 @@ async function ensureValidCopy(
}
}
return destStat;
return destStat!;
}
function ensureValidCopySync(
@ -48,7 +48,7 @@ function ensureValidCopySync(
options: CopyOptions,
isCopyFolder: boolean = false
): Deno.FileInfo {
let destStat: Deno.FileInfo;
let destStat: Deno.FileInfo | null;
try {
destStat = Deno.lstatSync(dest);
@ -56,8 +56,8 @@ function ensureValidCopySync(
// ignore error
}
if (destStat) {
if (isCopyFolder && !destStat.isDirectory()) {
if (destStat!) {
if (isCopyFolder && !destStat!.isDirectory()) {
throw new Error(
`Cannot overwrite non-directory '${dest}' with directory '${src}'.`
);
@ -67,7 +67,7 @@ function ensureValidCopySync(
}
}
return destStat;
return destStat!;
}
/* copy file to dest */
@ -80,7 +80,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 */
@ -89,7 +89,7 @@ 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);
Deno.utimeSync(dest, statInfo.accessed!, statInfo.modified!);
}
}
@ -105,7 +105,7 @@ 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);
await Deno.utime(dest, statInfo.accessed!, statInfo.modified!);
}
}
@ -121,7 +121,7 @@ function copySymlinkSync(
Deno.symlinkSync(originSrcFilePath, dest, type);
if (options.preserveTimestamps) {
const statInfo = Deno.lstatSync(src);
Deno.utimeSync(dest, statInfo.accessed, statInfo.modified);
Deno.utimeSync(dest, statInfo.accessed!, statInfo.modified!);
}
}
@ -139,13 +139,13 @@ async function copyDir(
if (options.preserveTimestamps) {
const srcStatInfo = await Deno.stat(src);
await Deno.utime(dest, srcStatInfo.accessed, srcStatInfo.modified);
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);
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);
@ -167,13 +167,13 @@ function copyDirSync(src: string, dest: string, options: CopyOptions): void {
if (options.preserveTimestamps) {
const srcStatInfo = Deno.statSync(src);
Deno.utimeSync(dest, srcStatInfo.accessed, srcStatInfo.modified);
Deno.utimeSync(dest, srcStatInfo.accessed!, srcStatInfo.modified!);
}
const files = Deno.readDirSync(src);
for (const file of files) {
const srcPath = path.join(src, file.name);
const srcPath = path.join(src, file.name!);
const destPath = path.join(dest, path.basename(srcPath as string));
if (file.isDirectory()) {
copyDirSync(srcPath, destPath, options);

View file

@ -66,7 +66,7 @@ export function globrex(
// Helper function to build string and segments
function add(
str,
str: string,
options: AddOptions = { split: false, last: false, only: "" }
): void {
const { split, last, only } = options;
@ -114,13 +114,13 @@ export function globrex(
if (c === ")") {
if (ext.length) {
add(c);
let type = ext.pop();
let type: string | undefined = ext.pop();
if (type === "@") {
add("{1}");
} else if (type === "!") {
add("([^/]*)");
} else {
add(type);
add(type as string);
}
continue;
}

View file

@ -5,29 +5,45 @@
import { test } from "../testing/mod.ts";
import { assertEquals } from "../testing/asserts.ts";
import { globrex, GlobrexResult } from "./globrex.ts";
import { GlobOptions } from "./glob.ts";
const isWin = Deno.build.os === "win";
const t = { equal: assertEquals, is: assertEquals };
function match(glob, strUnix, strWin?, opts = {}): boolean {
function match(
glob: string,
strUnix: string,
strWin?: string | object,
opts = {}
): boolean {
if (typeof strWin === "object") {
opts = strWin;
strWin = false;
strWin = "";
}
let res = globrex(glob, opts);
return res.regex.test(isWin && strWin ? strWin : strUnix);
}
function matchRegex(t, pattern, ifUnix, ifWin, opts): GlobrexResult {
function matchRegex(
pattern: string,
ifUnix: string,
ifWin: string,
opts: GlobOptions
): GlobrexResult {
const res = globrex(pattern, opts);
const { regex } = opts.filepath ? res.path : res;
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): GlobrexResult {
function matchSegments(
pattern: string,
ifUnix: RegExp[],
ifWin: RegExp[],
opts: GlobOptions
): GlobrexResult {
const res = globrex(pattern, { filepath: true, ...opts });
const str = res.path.segments.join(" ");
const str = res.path!.segments.join(" ");
const exp = (isWin ? ifWin : ifUnix).join(" ");
t.is(str, exp);
return res;
@ -191,7 +207,7 @@ test({
t.equal(match("f?o", "fooo", { extended: true }), false);
t.equal(match("f?oo", "foo", { extended: true }), false);
const tester = (globstar): void => {
const tester = (globstar: boolean): void => {
t.equal(
match("f?o", "foo", { extended: true, globstar, flags: "g" }),
true
@ -235,7 +251,7 @@ test({
t.equal(match("fo[!tz]", "fot", { extended: true }), false);
t.equal(match("fo[!tz]", "fob", { extended: true }), true);
const tester = (globstar): void => {
const tester = (globstar: boolean): void => {
t.equal(
match("fo[oz]", "foo", { extended: true, globstar, flags: "g" }),
true
@ -321,7 +337,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): void => {
const tester = (globstar: boolean): void => {
t.equal(
match("foo{bar,baaz}", "foobaaz", {
extended: true,
@ -405,7 +421,7 @@ test({
false
);
const tester = (globstar): void => {
const tester = (globstar: boolean): void => {
t.equal(
match(
"http://?o[oz].b*z.com/{*.js,*.html}",
@ -456,7 +472,7 @@ test({
test({
name: "globrex: standard globstar",
fn(): void {
const tester = (globstar): void => {
const tester = (globstar: boolean): void => {
t.equal(
match(
"http://foo.com/**/{*.js,*.html}",
@ -491,7 +507,7 @@ test({
test({
name: "globrex: remaining chars should match themself",
fn(): void {
const tester = (globstar): void => {
const tester = (globstar: boolean): void => {
const testExtStr = "\\/$^+.()=!|,.*";
t.equal(match(testExtStr, testExtStr, { extended: true }), true);
t.equal(
@ -801,47 +817,43 @@ test({
res = globrex("", opts);
t.is(res.hasOwnProperty("path"), true);
t.is(res.path.hasOwnProperty("regex"), true);
t.is(res.path.hasOwnProperty("segments"), true);
t.is(Array.isArray(res.path.segments), true);
t.is(res.path!.hasOwnProperty("regex"), true);
t.is(res.path!.hasOwnProperty("segments"), true);
t.is(Array.isArray(res.path!.segments), true);
pattern = "foo/bar/baz.js";
res = matchRegex(
t,
pattern,
"/^foo\\/bar\\/baz\\.js$/",
"/^foo\\\\+bar\\\\+baz\\.js$/",
opts
);
t.is(res.path.segments.length, 3);
t.is(res.path!.segments.length, 3);
res = matchRegex(
t,
"../foo/bar.js",
"/^\\.\\.\\/foo\\/bar\\.js$/",
"/^\\.\\.\\\\+foo\\\\+bar\\.js$/",
opts
);
t.is(res.path.segments.length, 3);
t.is(res.path!.segments.length, 3);
res = matchRegex(
t,
"*/bar.js",
"/^.*\\/bar\\.js$/",
"/^.*\\\\+bar\\.js$/",
opts
);
t.is(res.path.segments.length, 2);
t.is(res.path!.segments.length, 2);
opts.globstar = true;
res = matchRegex(
t,
"**/bar.js",
"/^((?:[^\\/]*(?:\\/|$))*)bar\\.js$/",
"/^((?:[^\\\\]*(?:\\\\|$))*)bar\\.js$/",
opts
);
t.is(res.path.segments.length, 2);
t.is(res.path!.segments.length, 2);
}
});
@ -854,42 +866,42 @@ test({
unix = [/^foo$/, /^bar$/, /^([^\/]*)$/, /^baz\.(md|js|txt)$/];
win = [/^foo$/, /^bar$/, /^([^\\]*)$/, /^baz\.(md|js|txt)$/];
matchSegments(t, "foo/bar/*/baz.{md,js,txt}", unix, win, {
matchSegments("foo/bar/*/baz.{md,js,txt}", unix, win, {
...opts,
globstar: true
});
unix = [/^foo$/, /^.*$/, /^baz\.md$/];
win = [/^foo$/, /^.*$/, /^baz\.md$/];
matchSegments(t, "foo/*/baz.md", unix, win, opts);
matchSegments("foo/*/baz.md", unix, win, opts);
unix = [/^foo$/, /^.*$/, /^baz\.md$/];
win = [/^foo$/, /^.*$/, /^baz\.md$/];
matchSegments(t, "foo/**/baz.md", unix, win, opts);
matchSegments("foo/**/baz.md", unix, win, opts);
unix = [/^foo$/, /^((?:[^\/]*(?:\/|$))*)$/, /^baz\.md$/];
win = [/^foo$/, /^((?:[^\\]*(?:\\|$))*)$/, /^baz\.md$/];
matchSegments(t, "foo/**/baz.md", unix, win, { ...opts, globstar: true });
matchSegments("foo/**/baz.md", unix, win, { ...opts, globstar: true });
unix = [/^foo$/, /^.*$/, /^.*\.md$/];
win = [/^foo$/, /^.*$/, /^.*\.md$/];
matchSegments(t, "foo/**/*.md", unix, win, opts);
matchSegments("foo/**/*.md", unix, win, opts);
unix = [/^foo$/, /^((?:[^\/]*(?:\/|$))*)$/, /^([^\/]*)\.md$/];
win = [/^foo$/, /^((?:[^\\]*(?:\\|$))*)$/, /^([^\\]*)\.md$/];
matchSegments(t, "foo/**/*.md", unix, win, { ...opts, globstar: true });
matchSegments("foo/**/*.md", unix, win, { ...opts, globstar: true });
unix = [/^foo$/, /^:$/, /^b:az$/];
win = [/^foo$/, /^:$/, /^b:az$/];
matchSegments(t, "foo/:/b:az", unix, win, opts);
matchSegments("foo/:/b:az", unix, win, opts);
unix = [/^foo$/, /^baz\.md$/];
win = [/^foo$/, /^baz\.md$/];
matchSegments(t, "foo///baz.md", unix, win, { ...opts, strict: true });
matchSegments("foo///baz.md", unix, win, { ...opts, strict: true });
unix = [/^foo$/, /^baz\.md$/];
win = [/^foo$/, /^baz\.md$/];
matchSegments(t, "foo///baz.md", unix, win, { ...opts, strict: false });
matchSegments("foo///baz.md", unix, win, { ...opts, strict: false });
}
});

View file

@ -108,18 +108,21 @@ const windowsJoinTests = [
test(function join() {
joinTests.forEach(function(p) {
const actual = path.posix.join.apply(null, p[0]);
const _p = p[0] as string[];
const actual = path.posix.join.apply(null, _p);
assertEquals(actual, p[1]);
});
});
test(function joinWin32() {
joinTests.forEach(function(p) {
const actual = path.win32.join.apply(null, p[0]).replace(backslashRE, "/");
const _p = p[0] as string[];
const actual = path.win32.join.apply(null, _p).replace(backslashRE, "/");
assertEquals(actual, p[1]);
});
windowsJoinTests.forEach(function(p) {
const actual = path.win32.join.apply(null, p[0]);
const _p = p[0] as string[];
const actual = path.win32.join.apply(null, _p);
assertEquals(actual, p[1]);
});
});

View file

@ -79,8 +79,8 @@ const unixSpecialCaseFormatTests = [
[{}, ""]
];
function checkParseFormat(path, paths): void {
paths.forEach(function(p) {
function checkParseFormat(path: any, paths: any): void {
paths.forEach(function(p: Record<string, unknown>[]) {
const element = p[0];
const output = path.parse(element);
assertEquals(typeof output.root, "string");
@ -95,8 +95,8 @@ function checkParseFormat(path, paths): void {
});
}
function checkSpecialCaseParseFormat(path, testCases): void {
testCases.forEach(function(testCase) {
function checkSpecialCaseParseFormat(path: any, testCases: any): void {
testCases.forEach(function(testCase: Record<string, unknown>[]) {
const element = testCase[0];
const expect = testCase[1];
const output = path.parse(element);
@ -106,7 +106,7 @@ function checkSpecialCaseParseFormat(path, testCases): void {
});
}
function checkFormat(path, testCases): void {
function checkFormat(path: any, testCases: unknown[][]): void {
testCases.forEach(function(testCase) {
assertEquals(path.format(testCase[0]), testCase[1]);
});

View file

@ -37,14 +37,16 @@ const posixTests =
test(function resolve() {
posixTests.forEach(function(p) {
const actual = path.posix.resolve.apply(null, p[0]);
const _p = p[0] as string[];
const actual = path.posix.resolve.apply(null, _p);
assertEquals(actual, p[1]);
});
});
test(function resolveWin32() {
windowsTests.forEach(function(p) {
const actual = path.win32.resolve.apply(null, p[0]);
const _p = p[0] as string[];
const actual = path.win32.resolve.apply(null, _p);
assertEquals(actual, p[1]);
});
});

View file

@ -49,7 +49,7 @@ export function normalizeString(
let code: number;
for (let i = 0, len = path.length; i <= len; ++i) {
if (i < len) code = path.charCodeAt(i);
else if (isPathSeparator(code)) break;
else if (isPathSeparator(code!)) break;
else code = CHAR_FORWARD_SLASH;
if (isPathSeparator(code)) {
@ -107,7 +107,7 @@ export function _format(
sep: string,
pathObject: FormatInputPathObject
): string {
const dir: string | null = pathObject.dir || pathObject.root;
const dir: string | undefined = pathObject.dir || pathObject.root;
const base: string =
pathObject.base || (pathObject.name || "") + (pathObject.ext || "");
if (!dir) return base;

View file

@ -171,7 +171,7 @@ export function normalize(path: string): string {
const len = path.length;
if (len === 0) return ".";
let rootEnd = 0;
let device: string;
let device: string | undefined;
let isAbsolute = false;
const code = path.charCodeAt(0);
@ -301,7 +301,7 @@ export function join(...paths: string[]): string {
const pathsCount = paths.length;
if (pathsCount === 0) return ".";
let joined: string;
let joined: string | undefined;
let firstPart: string;
for (let i = 0; i < pathsCount; ++i) {
let path = paths[i];
@ -329,6 +329,7 @@ export function join(...paths: string[]): string {
// path.join('//server', 'share') -> '\\\\server\\share\\')
let needsReplace = true;
let slashCount = 0;
firstPart = firstPart!;
if (isPathSeparator(firstPart.charCodeAt(0))) {
++slashCount;
const firstLen = firstPart.length;

View file

@ -16,10 +16,14 @@ export function isSubdir(
}
const srcArray = src.split(sep);
const destArray = dest.split(sep);
return srcArray.reduce((acc, current, i): boolean => {
return acc && destArray[i] === current;
}, true);
// see: https://github.com/Microsoft/TypeScript/issues/30821
return srcArray.reduce(
// @ts-ignore
(acc: true, current: string, i: number): boolean => {
return acc && destArray[i] === current;
},
true
);
}
export type PathType = "file" | "dir" | "symlink";
@ -29,7 +33,7 @@ export type PathType = "file" | "dir" | "symlink";
*
* @param fileInfo A FileInfo describes a file and is returned by `stat`, `lstat`
*/
export function getFileInfoType(fileInfo: Deno.FileInfo): PathType {
export function getFileInfoType(fileInfo: Deno.FileInfo): PathType | undefined {
return fileInfo.isFile()
? "file"
: fileInfo.isDirectory()

View file

@ -71,7 +71,7 @@ export async function* walk(
root: string,
options: WalkOptions = {}
): AsyncIterableIterator<WalkInfo> {
options.maxDepth -= 1;
options.maxDepth! -= 1;
let ls: FileInfo[] = [];
try {
ls = await readDir(root);
@ -90,14 +90,14 @@ export async function* walk(
}
}
const filename = join(root, info.name);
const filename = join(root, info.name!);
if (info.isFile()) {
if (include(filename, options)) {
yield { filename, info };
}
} else {
if (!(options.maxDepth < 0)) {
if (!(options.maxDepth! < 0)) {
yield* walk(filename, options);
}
}
@ -109,7 +109,7 @@ export function* walkSync(
root: string = ".",
options: WalkOptions = {}
): IterableIterator<WalkInfo> {
options.maxDepth -= 1;
options.maxDepth! -= 1;
let ls: FileInfo[] = [];
try {
ls = readDirSync(root);
@ -127,14 +127,14 @@ export function* walkSync(
}
}
const filename = join(root, info.name);
const filename = join(root, info.name!);
if (info.isFile()) {
if (include(filename, options)) {
yield { filename, info };
}
} else {
if (!(options.maxDepth < 0)) {
if (!(options.maxDepth! < 0)) {
yield* walkSync(filename, options);
}
}

View file

@ -5,7 +5,7 @@ import { test, TestFunction, runIfMain } from "../testing/mod.ts";
import { assertEquals } from "../testing/asserts.ts";
export async function testWalk(
setup: (string) => void | Promise<void>,
setup: (arg0: string) => void | Promise<void>,
t: TestFunction
): Promise<void> {
const name = t.name;

View file

@ -45,8 +45,8 @@ function toString(cookie: Cookie): string {
if (cookie.httpOnly) {
out.push("HttpOnly");
}
if (Number.isInteger(cookie.maxAge)) {
assert(cookie.maxAge > 0, "Max-Age must be an integer superior to 0");
if (Number.isInteger(cookie.maxAge!)) {
assert(cookie.maxAge! > 0, "Max-Age must be an integer superior to 0");
out.push(`Max-Age=${cookie.maxAge}`);
}
if (cookie.domain) {
@ -75,10 +75,10 @@ function toString(cookie: Cookie): string {
export function getCookies(req: ServerRequest): Cookies {
if (req.headers.has("Cookie")) {
const out: Cookies = {};
const c = req.headers.get("Cookie").split(";");
const c = req.headers.get("Cookie")!.split(";");
for (const kv of c) {
const cookieVal = kv.split("=");
const key = cookieVal.shift().trim();
const key = cookieVal.shift()!.trim();
out[key] = cookieVal.join("=");
}
return out;

View file

@ -38,7 +38,7 @@ test({
let res: Response = {};
delCookie(res, "deno");
assertEquals(
res.headers.get("Set-Cookie"),
res.headers!.get("Set-Cookie"),
"deno=; Expires=Thus, 01 Jan 1970 00:00:00 GMT"
);
}

View file

@ -6,7 +6,8 @@ import { assert, assertEquals } from "../testing/asserts.ts";
import { BufReader, EOF } from "../io/bufio.ts";
import { TextProtoReader } from "../textproto/mod.ts";
let fileServer;
let fileServer: Deno.Process;
async function startFileServer(): Promise<void> {
fileServer = run({
args: [
@ -21,14 +22,14 @@ async function startFileServer(): Promise<void> {
stdout: "piped"
});
// Once fileServer is ready it will write to its stdout.
const r = new TextProtoReader(new BufReader(fileServer.stdout));
const r = new TextProtoReader(new BufReader(fileServer.stdout!));
const s = await r.readLine();
assert(s !== EOF && s.includes("server listening"));
}
function killFileServer(): void {
fileServer.close();
fileServer.stdout.close();
fileServer.stdout!.close();
}
test(async function serveFile(): Promise<void> {

View file

@ -5,20 +5,20 @@ import { assert, assertEquals } from "../testing/asserts.ts";
import { BufReader, EOF } from "../io/bufio.ts";
import { TextProtoReader } from "../textproto/mod.ts";
let server;
let server: Deno.Process;
async function startServer(): Promise<void> {
server = run({
args: ["deno", "run", "-A", "http/racing_server.ts"],
stdout: "piped"
});
// Once fileServer is ready it will write to its stdout.
const r = new TextProtoReader(new BufReader(server.stdout));
const r = new TextProtoReader(new BufReader(server.stdout!));
const s = await r.readLine();
assert(s !== EOF && s.includes("Racing server listening..."));
}
function killServer(): void {
server.close();
server.stdout.close();
server.stdout!.close();
}
let input = `GET / HTTP/1.1

View file

@ -73,11 +73,10 @@ export async function writeResponse(w: Writer, r: Response): Promise<void> {
let out = `HTTP/${protoMajor}.${protoMinor} ${statusCode} ${statusText}\r\n`;
setContentLength(r);
const headers = r.headers!;
if (r.headers) {
for (const [key, value] of r.headers) {
out += `${key}: ${value}\r\n`;
}
for (const [key, value] of headers!) {
out += `${key}: ${value}\r\n`;
}
out += "\r\n";
@ -88,8 +87,8 @@ export async function writeResponse(w: Writer, r: Response): Promise<void> {
if (r.body instanceof Uint8Array) {
const n = await writer.write(r.body);
assert(n === r.body.byteLength);
} else if (r.headers.has("content-length")) {
const bodyLength = parseInt(r.headers.get("content-length"));
} else if (headers.has("content-length")) {
const bodyLength = parseInt(headers.get("content-length")!);
const n = await copy(writer, r.body);
assert(n === bodyLength);
} else {
@ -99,19 +98,19 @@ export async function writeResponse(w: Writer, r: Response): Promise<void> {
}
export class ServerRequest {
url: string;
method: string;
proto: string;
protoMinor: number;
protoMajor: number;
headers: Headers;
r: BufReader;
w: BufWriter;
url!: string;
method!: string;
proto!: string;
protoMinor!: number;
protoMajor!: number;
headers!: Headers;
r!: BufReader;
w!: BufWriter;
done: Deferred<void> = deferred();
public async *bodyStream(): AsyncIterableIterator<Uint8Array> {
if (this.headers.has("content-length")) {
const len = +this.headers.get("content-length");
const len = +this.headers.get("content-length")!;
if (Number.isNaN(len)) {
return new Uint8Array(0);
}
@ -128,7 +127,7 @@ export class ServerRequest {
} else {
if (this.headers.has("transfer-encoding")) {
const transferEncodings = this.headers
.get("transfer-encoding")
.get("transfer-encoding")!
.split(",")
.map((e): string => e.trim().toLowerCase());
if (transferEncodings.includes("chunked")) {
@ -334,14 +333,14 @@ export class Server implements AsyncIterable<ServerRequest> {
// Wait for the request to be processed before we accept a new request on
// this connection.
await req.done;
await req!.done;
}
if (req === EOF) {
if (req! === EOF) {
// The connection was gracefully closed.
} else if (err) {
// An error was thrown while parsing request headers.
await writeResponse(req.w, {
await writeResponse(req!.w, {
status: 400,
body: new TextEncoder().encode(`${err.message}\r\n\r\n`)
});

View file

@ -336,65 +336,64 @@ malformedHeader
// https://github.com/golang/go/blob/go1.12.5/src/net/http/request_test.go#L377-L443
// TODO(zekth) fix tests
test(async function testReadRequestError(): Promise<void> {
const testCases = {
0: {
const testCases = [
{
in: "GET / HTTP/1.1\r\nheader: foo\r\n\r\n",
headers: [{ key: "header", value: "foo" }]
},
1: {
{
in: "GET / HTTP/1.1\r\nheader:foo\r\n",
err: UnexpectedEOFError
},
2: { in: "", err: EOF },
3: {
{ in: "", err: EOF },
{
in: "HEAD / HTTP/1.1\r\nContent-Length:4\r\n\r\n",
err: "http: method cannot contain a Content-Length"
},
4: {
{
in: "HEAD / HTTP/1.1\r\n\r\n",
headers: []
},
// Multiple Content-Length values should either be
// deduplicated if same or reject otherwise
// See Issue 16490.
5: {
{
in:
"POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 0\r\n\r\nGopher hey\r\n",
err: "cannot contain multiple Content-Length headers"
},
6: {
{
in:
"POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 6\r\n\r\nGopher\r\n",
err: "cannot contain multiple Content-Length headers"
},
7: {
{
in:
"PUT / HTTP/1.1\r\nContent-Length: 6 \r\nContent-Length: 6\r\nContent-Length:6\r\n\r\nGopher\r\n",
headers: [{ key: "Content-Length", value: "6" }]
},
8: {
{
in: "PUT / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 6 \r\n\r\n",
err: "cannot contain multiple Content-Length headers"
},
// Setting an empty header is swallowed by textproto
// see: readMIMEHeader()
// 9: {
// {
// in: "POST / HTTP/1.1\r\nContent-Length:\r\nContent-Length: 3\r\n\r\n",
// err: "cannot contain multiple Content-Length headers"
// },
10: {
{
in: "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n",
headers: [{ key: "Content-Length", value: "0" }]
},
11: {
{
in:
"POST / HTTP/1.1\r\nContent-Length:0\r\ntransfer-encoding: chunked\r\n\r\n",
headers: [],
err: "http: Transfer-Encoding and Content-Length cannot be send together"
}
};
for (const p in testCases) {
const test = testCases[p];
];
for (const test of testCases) {
const reader = new BufReader(new StringReader(test.in));
let err;
let req;
@ -408,12 +407,12 @@ test(async function testReadRequestError(): Promise<void> {
} else if (typeof test.err === "string") {
assertEquals(err.message, test.err);
} else if (test.err) {
assert(err instanceof test.err);
assert(err instanceof (test.err as typeof UnexpectedEOFError));
} else {
assertEquals(err, undefined);
assertNotEquals(req, EOF);
for (const h of test.headers) {
assertEquals(req.headers.get(h.key), h.value);
for (const h of test.headers!) {
assertEquals((req! as ServerRequest).headers.get(h.key), h.value);
}
}
}

View file

@ -40,8 +40,8 @@ export interface ReadLineResult {
/** BufReader implements buffering for a Reader object. */
export class BufReader implements Reader {
private buf: Uint8Array;
private rd: Reader; // Reader provided by caller.
private buf!: Uint8Array;
private rd!: Reader; // Reader provided by caller.
private r = 0; // buf read position.
private w = 0; // buf write position.
private eof = false;
@ -342,7 +342,7 @@ export class BufReader implements Reader {
try {
await this._fill();
} catch (err) {
err.partial = slice;
err.partial = slice!;
throw err;
}
}
@ -439,7 +439,7 @@ export class BufWriter implements Writer {
if (this.err !== null) throw this.err;
if (this.n === 0) return;
let n: number;
let n = 0;
try {
n = await this.wr.write(this.buf.subarray(0, this.n));
} catch (e) {
@ -479,7 +479,7 @@ export class BufWriter implements Writer {
if (p.length === 0) return 0;
let nn = 0;
let n: number;
let n = 0;
while (p.byteLength > this.available()) {
if (this.buffered() === 0) {
// Large write, empty buffer.

View file

@ -6,6 +6,7 @@ import { decode, encode } from "../strings/mod.ts";
export class StringWriter implements Writer {
private chunks: Uint8Array[] = [];
private byteLength: number = 0;
private cache: string | undefined;
constructor(private base: string = "") {
const c = encode(base);
@ -16,12 +17,10 @@ export class StringWriter implements Writer {
async write(p: Uint8Array): Promise<number> {
this.chunks.push(p);
this.byteLength += p.byteLength;
this.cache = null;
this.cache = undefined;
return p.byteLength;
}
private cache: string;
toString(): string {
if (this.cache) {
return this.cache;
@ -33,6 +32,6 @@ export class StringWriter implements Writer {
offs += chunk.byteLength;
}
this.cache = decode(buf);
return this.cache;
return this.cache!;
}
}

View file

@ -40,14 +40,14 @@ export class BaseHandler {
return this.formatter.replace(
/{(\S+)}/g,
(match, p1): string => {
const value = logRecord[p1];
const value = logRecord[p1 as keyof LogRecord];
// do not interpolate missing values
if (!value) {
return match;
}
return value;
return String(value);
}
);
}
@ -87,7 +87,7 @@ export class ConsoleHandler extends BaseHandler {
}
export abstract class WriterHandler extends BaseHandler {
protected _writer: Writer;
protected _writer!: Writer;
private _encoder = new TextEncoder();
log(msg: string): void {
@ -100,7 +100,7 @@ interface FileHandlerOptions extends HandlerOptions {
}
export class FileHandler extends WriterHandler {
private _file: File;
private _file!: File;
private _filename: string;
constructor(levelName: string, options: FileHandlerOptions) {

View file

@ -1,5 +1,5 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
export const LogLevel = {
export const LogLevel: Record<string, number> = {
NOTSET: 0,
DEBUG: 10,
INFO: 20,
@ -8,15 +8,6 @@ export const LogLevel = {
CRITICAL: 50
};
const byName = {
NOTSET: LogLevel.NOTSET,
DEBUG: LogLevel.DEBUG,
INFO: LogLevel.INFO,
WARNING: LogLevel.WARNING,
ERROR: LogLevel.ERROR,
CRITICAL: LogLevel.CRITICAL
};
const byLevel = {
[LogLevel.NOTSET]: "NOTSET",
[LogLevel.DEBUG]: "DEBUG",
@ -27,7 +18,7 @@ const byLevel = {
};
export function getLevelByName(name: string): number {
return byName[name];
return LogLevel[name];
}
export function getLevelName(level: number): string {

View file

@ -10,7 +10,7 @@ class TestHandler extends BaseHandler {
public records: LogRecord[] = [];
handle(record: LogRecord): void {
this.records.push({ ...record, datetime: null });
this.records.push({ ...record });
super.handle(record);
}
@ -38,33 +38,29 @@ test(function customHandler(): void {
logger.debug("foo", 1, 2);
assertEquals(handler.records, [
{
msg: "foo",
args: [1, 2],
datetime: null,
level: LogLevel.DEBUG,
levelName: "DEBUG"
}
]);
const record = handler.records[0];
assertEquals(record.msg, "foo");
assertEquals(record.args, [1, 2]);
assertEquals(record.level, LogLevel.DEBUG);
assertEquals(record.levelName, "DEBUG");
assertEquals(handler.messages, ["DEBUG foo"]);
});
test(function logFunctions(): void {
let handler: TestHandler;
const doLog = (level: string): void => {
handler = new TestHandler(level);
const doLog = (level: string): TestHandler => {
const handler = new TestHandler(level);
let logger = new Logger(level, [handler]);
logger.debug("foo");
logger.info("bar");
logger.warning("baz");
logger.error("boo");
logger.critical("doo");
return handler;
};
doLog("DEBUG");
let handler: TestHandler;
handler = doLog("DEBUG");
assertEquals(handler.messages, [
"DEBUG foo",
@ -74,7 +70,7 @@ test(function logFunctions(): void {
"CRITICAL doo"
]);
doLog("INFO");
handler = doLog("INFO");
assertEquals(handler.messages, [
"INFO bar",
@ -83,15 +79,15 @@ test(function logFunctions(): void {
"CRITICAL doo"
]);
doLog("WARNING");
handler = doLog("WARNING");
assertEquals(handler.messages, ["WARNING baz", "ERROR boo", "CRITICAL doo"]);
doLog("ERROR");
handler = doLog("ERROR");
assertEquals(handler.messages, ["ERROR boo", "CRITICAL doo"]);
doLog("CRITICAL");
handler = doLog("CRITICAL");
assertEquals(handler.messages, ["CRITICAL doo"]);
});

View file

@ -50,7 +50,7 @@ export const handlers = {
export function getLogger(name?: string): Logger {
if (!name) {
return state.loggers.get("default");
return state.loggers.get("default")!;
}
if (!state.loggers.has(name)) {
@ -59,7 +59,7 @@ export function getLogger(name?: string): Logger {
return logger;
}
return state.loggers.get(name);
return state.loggers.get(name)!;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -78,10 +78,6 @@ export const error = (msg: string, ...args: any[]): void =>
export const critical = (msg: string, ...args: any[]): void =>
getLogger("default").critical(msg, ...args);
export function getHandler(name: string): BaseHandler {
return state.handlers.get(name);
}
export async function setup(config: LogConfig): Promise<void> {
state.config = {
handlers: { ...DEFAULT_CONFIG.handlers, ...config.handlers },
@ -118,7 +114,7 @@ export async function setup(config: LogConfig): Promise<void> {
handlerNames.forEach(
(handlerName): void => {
if (state.handlers.has(handlerName)) {
handlers.push(state.handlers.get(handlerName));
handlers.push(state.handlers.get(handlerName)!);
}
}
);

View file

@ -16,7 +16,8 @@ class TestHandler extends log.handlers.BaseHandler {
}
test(async function defaultHandlers(): Promise<void> {
const loggers = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const loggers: { [key: string]: (msg: string, ...args: any[]) => void } = {
DEBUG: log.debug,
INFO: log.info,
WARNING: log.warning,
@ -29,9 +30,8 @@ test(async function defaultHandlers(): Promise<void> {
continue;
}
const level = LogLevel[levelName];
const logger = loggers[levelName];
const handler = new TestHandler(level);
const handler = new TestHandler(levelName);
await log.setup({
handlers: {

View file

@ -177,20 +177,20 @@ class PartReader implements Reader, Closer {
close(): void {}
private contentDisposition: string;
private contentDispositionParams: { [key: string]: string };
private contentDisposition!: string;
private contentDispositionParams!: { [key: string]: string };
private getContentDispositionParams(): { [key: string]: string } {
if (this.contentDispositionParams) return this.contentDispositionParams;
const cd = this.headers.get("content-disposition");
const params = {};
const comps = cd.split(";");
const params: { [key: string]: string } = {};
const comps = cd!.split(";");
this.contentDisposition = comps[0];
comps
.slice(1)
.map((v): string => v.trim())
.map((v: string): string => v.trim())
.map(
(kv): void => {
(kv: string): void => {
const [k, v] = kv.split("=");
if (v) {
const s = v.charAt(0);
@ -292,7 +292,7 @@ export class MultipartReader {
file.close();
formFile = {
filename: p.fileName,
type: p.headers.get("content-type"),
type: p.headers.get("content-type")!,
tempfile: filepath,
size
};
@ -302,20 +302,20 @@ export class MultipartReader {
} else {
formFile = {
filename: p.fileName,
type: p.headers.get("content-type"),
type: p.headers.get("content-type")!,
content: buf.bytes(),
size: buf.length
};
maxMemory -= n;
maxValueBytes -= n;
}
result[p.formName] = formFile;
result[p.formName] = formFile!;
}
return result;
}
private currentPart: PartReader;
private partsRead: number;
private currentPart: PartReader | undefined;
private partsRead: number = 0;
private async nextPart(): Promise<PartReader | EOF> {
if (this.currentPart) {
@ -437,7 +437,7 @@ export class MultipartWriter {
return this._boundary;
}
private lastPart: PartWriter;
private lastPart: PartWriter | undefined;
private bufWriter: BufWriter;
private isClosed: boolean = false;

View file

@ -142,6 +142,7 @@ test(async function multipartMultipartWriter3(): Promise<void> {
);
await assertThrowsAsync(
async (): Promise<void> => {
// @ts-ignore
await mw.writeFile("bar", "file", null);
},
Error,
@ -197,7 +198,7 @@ test(async function multipartMultipartReader2(): Promise<void> {
assertEquals(form["bar"], "bar");
const file = form["file"] as FormFile;
assertEquals(file.type, "application/octet-stream");
const f = await open(file.tempfile);
const f = await open(file.tempfile!);
const w = new StringWriter();
await copy(w, f);
const json = JSON.parse(w.toString());
@ -205,7 +206,7 @@ test(async function multipartMultipartReader2(): Promise<void> {
f.close();
} finally {
const file = form["file"] as FormFile;
await remove(file.tempfile);
await remove(file.tempfile!);
}
});

View file

@ -13,7 +13,7 @@ async function run(
): Promise<{ stdout: string; code: number | undefined }> {
const p = xrun({ args, stdout: "piped" });
const stdout = decoder.decode(await readAll(p.stdout));
const stdout = decoder.decode(await readAll(p.stdout!));
const { code } = await p.status();
return { stdout, code };

View file

@ -1,2 +1,6 @@
console.log(0)
console.log([function foo() {}, function baz() {}, a => {}])
console.log(0);
console.log([
function foo() {},
function baz() {},
a => {}
]);

View file

@ -2,7 +2,7 @@
const { build, run } = Deno;
// Runs a command in cross-platform way
export function xrun(opts): Deno.Process {
export function xrun(opts: Deno.RunOptions): Deno.Process {
return run({
...opts,
args: build.os === "win" ? ["cmd.exe", "/c", ...opts.args] : opts.args

View file

@ -183,7 +183,7 @@ export function assertArrayContains(
expected: unknown[],
msg?: string
): void {
let missing = [];
let missing: unknown[] = [];
for (let i = 0; i < expected.length; i++) {
let found = false;
for (let j = 0; j < actual.length; j++) {

View file

@ -525,16 +525,10 @@ const getConfig = (options: Options): Config => ({
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function format(val: any, options: Optional<Options> = {}): string {
const opts = Object.keys(DEFAULT_OPTIONS).reduce(
(acc: Options, k: keyof Options): unknown => {
const opt = options[k];
if (typeof opt === "undefined") {
return { ...acc, [k]: DEFAULT_OPTIONS[k] };
}
return { ...acc, [k]: opt };
},
{}
) as Options;
const opts: Options = {
...DEFAULT_OPTIONS,
...options
};
const basicResult = printBasicValue(val, opts);
if (basicResult !== null) {
return basicResult;

View file

@ -54,7 +54,7 @@ interface TestStats {
interface TestResult {
name: string;
error: Error;
error?: Error;
ok: boolean;
printed: boolean;
}
@ -68,7 +68,7 @@ function createTestResults(tests: TestDefinition[]): TestResults {
return tests.reduce(
(acc: TestResults, { name }: TestDefinition, i: number): TestResults => {
acc.keys.set(name, i);
acc.cases.set(i, { name, printed: false, ok: false, error: null });
acc.cases.set(i, { name, printed: false, ok: false, error: undefined });
return acc;
},
{ cases: new Map(), keys: new Map() }
@ -114,11 +114,11 @@ function printResults(
}
function previousPrinted(name: string, results: TestResults): boolean {
const curIndex: number = results.keys.get(name);
const curIndex: number = results.keys.get(name)!;
if (curIndex === 0) {
return true;
}
return results.cases.get(curIndex - 1).printed;
return results.cases.get(curIndex - 1)!.printed;
}
async function createTestCase(
@ -127,7 +127,7 @@ async function createTestCase(
exitOnFail: boolean,
{ fn, name }: TestDefinition
): Promise<void> {
const result: TestResult = results.cases.get(results.keys.get(name));
const result: TestResult = results.cases.get(results.keys.get(name)!)!;
try {
await fn();
stats.passed++;

View file

@ -38,7 +38,7 @@ function createSign(diffType: DiffType): string {
}
function buildMessage(diffResult: ReadonlyArray<DiffResult<string>>): string[] {
const messages = [];
const messages: string[] = [];
messages.push("");
messages.push("");
messages.push(

View file

@ -82,7 +82,7 @@ export class TextProtoReader {
throw new UnexpectedEOFError();
} else if (buf[0] == charCode(" ") || buf[0] == charCode("\t")) {
throw new ProtocolError(
`malformed MIME header initial line: ${str(line)}`
`malformed MIME header initial line: ${str(line!)}`
);
}
@ -140,7 +140,7 @@ export class TextProtoReader {
const { line: l, more } = r;
// Avoid the copy if the first call produced a full line.
if (!line && !more) {
if (!line! && !more) {
// TODO(ry):
// This skipSpace() is definitely misplaced, but I don't know where it
// comes from nor how to fix it.
@ -150,6 +150,7 @@ export class TextProtoReader {
return l;
}
// @ts-ignore
line = append(line, l);
if (!more) {
break;

View file

@ -83,7 +83,7 @@ test({
test({
name: "[textproto] Reader : Large MIME Header",
async fn(): Promise<void> {
const data = [];
const data: string[] = [];
// Go test is 16*1024. But seems it can't handle more
for (let i = 0; i < 1024; i++) {
data.push("x");

View file

@ -1,4 +1,5 @@
{
"extends": "tsconfig.test.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",
@ -7,7 +8,6 @@
"noEmit": true,
"pretty": true,
"resolveJsonModule": true,
"strict": true,
"target": "esnext",
"lib": ["esnext"]
},

5
tsconfig.test.json Normal file
View file

@ -0,0 +1,5 @@
{
"compilerOptions": {
"strict": true
}
}

View file

@ -25,7 +25,7 @@ export function deferred<T>(): Deferred<T> {
methods = { resolve, reject };
}
);
return Object.assign(promise, methods) as Deferred<T>;
return Object.assign(promise, methods)! as Deferred<T>;
}
interface TaggedYieldedValue<T> {

View file

@ -1,12 +1,15 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
export function deepAssign(target: object, ...sources: object[]): object {
export function deepAssign(
target: Record<string, unknown>,
...sources: object[]
): object | undefined {
for (let i = 0; i < sources.length; i++) {
const source = sources[i];
if (!source || typeof source !== `object`) {
return;
}
Object.entries(source).forEach(
([key, value]): void => {
([key, value]: [string, unknown]): void => {
if (value instanceof Date) {
target[key] = new Date(value);
return;
@ -22,7 +25,7 @@ export function deepAssign(target: object, ...sources: object[]): object {
if (typeof target[key] !== `object` || !target[key]) {
target[key] = {};
}
deepAssign(target[key], value);
deepAssign(target[key] as Record<string, unknown>, value!);
}
);
}

View file

@ -31,19 +31,25 @@ export interface WebSocketCloseEvent {
reason?: string;
}
export function isWebSocketCloseEvent(a): a is WebSocketCloseEvent {
return a && typeof a["code"] === "number";
export function isWebSocketCloseEvent(
a: WebSocketEvent
): a is WebSocketCloseEvent {
return typeof a === "object" && a.hasOwnProperty("code");
}
export type WebSocketPingEvent = ["ping", Uint8Array];
export function isWebSocketPingEvent(a): a is WebSocketPingEvent {
export function isWebSocketPingEvent(
a: WebSocketEvent
): a is WebSocketPingEvent {
return Array.isArray(a) && a[0] === "ping" && a[1] instanceof Uint8Array;
}
export type WebSocketPongEvent = ["pong", Uint8Array];
export function isWebSocketPongEvent(a): a is WebSocketPongEvent {
export function isWebSocketPongEvent(
a: WebSocketEvent
): a is WebSocketPongEvent {
return Array.isArray(a) && a[0] === "pong" && a[1] instanceof Uint8Array;
}
@ -436,6 +442,8 @@ async function handshake(
if (!m) {
throw new Error("ws: invalid status line: " + statusLine);
}
// @ts-ignore
const { version, statusCode } = m.groups;
if (version !== "HTTP/1.1" || statusCode !== "101") {
throw new Error(

View file

@ -77,11 +77,11 @@ export class Sha1 {
if (notString) {
for (i = start; index < length && i < 64; ++index) {
blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
blocks[i >> 2] |= (message[index] as number) << SHIFT[i++ & 3];
}
} else {
for (i = start; index < length && i < 64; ++index) {
code = message.charCodeAt(index);
code = (message as string).charCodeAt(index);
if (code < 0x80) {
blocks[i >> 2] |= code << SHIFT[i++ & 3];
} else if (code < 0x800) {
@ -94,7 +94,8 @@ export class Sha1 {
} else {
code =
0x10000 +
(((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
(((code & 0x3ff) << 10) |
((message as string).charCodeAt(++index) & 0x3ff));
blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];

View file

@ -166,20 +166,31 @@ test(function wsAcceptable(): void {
);
});
const invalidHeaders = [
{ "sec-websocket-key": "aaa" },
{ upgrade: "websocket" },
{ upgrade: "invalid", "sec-websocket-key": "aaa" },
{ upgrade: "websocket", "sec-websocket-ky": "" }
];
test(function wsAcceptableInvalid(): void {
for (const pat of invalidHeaders) {
const ret = acceptable({
headers: new Headers(pat)
});
assertEquals(ret, false);
}
assertEquals(
acceptable({
headers: new Headers({ "sec-websocket-key": "aaa" })
}),
false
);
assertEquals(
acceptable({
headers: new Headers({ upgrade: "websocket" })
}),
false
);
assertEquals(
acceptable({
headers: new Headers({ upgrade: "invalid", "sec-websocket-key": "aaa" })
}),
false
);
assertEquals(
acceptable({
headers: new Headers({ upgrade: "websocket", "sec-websocket-ky": "" })
}),
false
);
});
test(async function wsWriteReadMaskedFrame(): Promise<void> {