mirror of
https://github.com/denoland/deno.git
synced 2025-01-03 04:48:52 -05:00
Web APIs: File
and FormData
(#1056)
This commit is contained in:
parent
1241b8e9ba
commit
e93d686e9d
10 changed files with 360 additions and 16 deletions
2
BUILD.gn
2
BUILD.gn
|
@ -87,10 +87,12 @@ ts_sources = [
|
||||||
"js/dom_types.ts",
|
"js/dom_types.ts",
|
||||||
"js/errors.ts",
|
"js/errors.ts",
|
||||||
"js/fetch.ts",
|
"js/fetch.ts",
|
||||||
|
"js/file.ts",
|
||||||
"js/headers.ts",
|
"js/headers.ts",
|
||||||
"js/file_info.ts",
|
"js/file_info.ts",
|
||||||
"js/files.ts",
|
"js/files.ts",
|
||||||
"js/flatbuffers.ts",
|
"js/flatbuffers.ts",
|
||||||
|
"js/form_data.ts",
|
||||||
"js/global_eval.ts",
|
"js/global_eval.ts",
|
||||||
"js/globals.ts",
|
"js/globals.ts",
|
||||||
"js/io.ts",
|
"js/io.ts",
|
||||||
|
|
|
@ -97,6 +97,12 @@ function toUint8Arrays(
|
||||||
ret.push(element[bytesSymbol]);
|
ret.push(element[bytesSymbol]);
|
||||||
} else if (element instanceof Uint8Array) {
|
} else if (element instanceof Uint8Array) {
|
||||||
ret.push(element);
|
ret.push(element);
|
||||||
|
} else if (element instanceof Uint16Array) {
|
||||||
|
const uint8 = new Uint8Array(element.buffer);
|
||||||
|
ret.push(uint8);
|
||||||
|
} else if (element instanceof Uint32Array) {
|
||||||
|
const uint8 = new Uint8Array(element.buffer);
|
||||||
|
ret.push(uint8);
|
||||||
} else if (ArrayBuffer.isView(element)) {
|
} else if (ArrayBuffer.isView(element)) {
|
||||||
// Convert view to Uint8Array.
|
// Convert view to Uint8Array.
|
||||||
const uint8 = new Uint8Array(element.buffer);
|
const uint8 = new Uint8Array(element.buffer);
|
||||||
|
@ -105,6 +111,8 @@ function toUint8Arrays(
|
||||||
// Create a new Uint8Array view for the given ArrayBuffer.
|
// Create a new Uint8Array view for the given ArrayBuffer.
|
||||||
const uint8 = new Uint8Array(element);
|
const uint8 = new Uint8Array(element);
|
||||||
ret.push(uint8);
|
ret.push(uint8);
|
||||||
|
} else {
|
||||||
|
ret.push(enc.encode(String(element)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -34,7 +34,7 @@ type ReferrerPolicy =
|
||||||
| "origin-when-cross-origin"
|
| "origin-when-cross-origin"
|
||||||
| "unsafe-url";
|
| "unsafe-url";
|
||||||
export type BlobPart = BufferSource | Blob | string;
|
export type BlobPart = BufferSource | Blob | string;
|
||||||
type FormDataEntryValue = File | string;
|
export type FormDataEntryValue = File | string;
|
||||||
export type EventListenerOrEventListenerObject =
|
export type EventListenerOrEventListenerObject =
|
||||||
| EventListener
|
| EventListener
|
||||||
| EventListenerObject;
|
| EventListenerObject;
|
||||||
|
@ -173,7 +173,7 @@ interface Event {
|
||||||
readonly NONE: number;
|
readonly NONE: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface File extends Blob {
|
export interface File extends Blob {
|
||||||
readonly lastModified: number;
|
readonly lastModified: number;
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
}
|
}
|
||||||
|
@ -242,22 +242,18 @@ interface ReadableStreamReader {
|
||||||
releaseLock(): void;
|
releaseLock(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FormData {
|
export interface FormData extends DomIterable<string, FormDataEntryValue> {
|
||||||
append(name: string, value: string | Blob, fileName?: string): void;
|
append(name: string, value: string | Blob, fileName?: string): void;
|
||||||
delete(name: string): void;
|
delete(name: string): void;
|
||||||
get(name: string): FormDataEntryValue | null;
|
get(name: string): FormDataEntryValue | null;
|
||||||
getAll(name: string): FormDataEntryValue[];
|
getAll(name: string): FormDataEntryValue[];
|
||||||
has(name: string): boolean;
|
has(name: string): boolean;
|
||||||
set(name: string, value: string | Blob, fileName?: string): void;
|
set(name: string, value: string | Blob, fileName?: string): void;
|
||||||
forEach(
|
}
|
||||||
callbackfn: (
|
|
||||||
value: FormDataEntryValue,
|
export interface FormDataConstructor {
|
||||||
key: string,
|
new (): FormData;
|
||||||
parent: FormData
|
prototype: FormData;
|
||||||
) => void,
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
thisArg?: any
|
|
||||||
): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A blob object represents a file-like object of immutable, raw data. */
|
/** A blob object represents a file-like object of immutable, raw data. */
|
||||||
|
|
24
js/file.ts
Normal file
24
js/file.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
||||||
|
import * as domTypes from "./dom_types";
|
||||||
|
import * as blob from "./blob";
|
||||||
|
|
||||||
|
export class DenoFile extends blob.DenoBlob implements domTypes.File {
|
||||||
|
lastModified: number;
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
fileBits: domTypes.BlobPart[],
|
||||||
|
fileName: string,
|
||||||
|
options?: domTypes.FilePropertyBag
|
||||||
|
) {
|
||||||
|
options = options || {};
|
||||||
|
super(fileBits, options);
|
||||||
|
|
||||||
|
// 4.1.2.1 Replace any "/" character (U+002F SOLIDUS)
|
||||||
|
// with a ":" (U + 003A COLON)
|
||||||
|
this.name = String(fileName).replace(/\u002F/g, "\u003A");
|
||||||
|
// 4.1.3.3 If lastModified is not provided, set lastModified to the current
|
||||||
|
// date and time represented in number of milliseconds since the Unix Epoch.
|
||||||
|
this.lastModified = options.lastModified || Date.now();
|
||||||
|
}
|
||||||
|
}
|
104
js/file_test.ts
Normal file
104
js/file_test.ts
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
||||||
|
import { test, assert, assertEqual } from "./test_util.ts";
|
||||||
|
|
||||||
|
function testFirstArgument(arg1, expectedSize) {
|
||||||
|
const file = new File(arg1, "name");
|
||||||
|
assert(file instanceof File);
|
||||||
|
assertEqual(file.name, "name");
|
||||||
|
assertEqual(file.size, expectedSize);
|
||||||
|
assertEqual(file.type, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
test(function fileEmptyFileBits() {
|
||||||
|
testFirstArgument([], 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileStringFileBits() {
|
||||||
|
testFirstArgument(["bits"], 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileUnicodeStringFileBits() {
|
||||||
|
testFirstArgument(["𝓽𝓮𝔁𝓽"], 16);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileStringObjectFileBits() {
|
||||||
|
// tslint:disable-next-line no-construct
|
||||||
|
testFirstArgument([new String("string object")], 13);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileEmptyBlobFileBits() {
|
||||||
|
testFirstArgument([new Blob()], 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileBlobFileBits() {
|
||||||
|
testFirstArgument([new Blob(["bits"])], 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileEmptyFileFileBits() {
|
||||||
|
testFirstArgument([new File([], "world.txt")], 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileFileFileBits() {
|
||||||
|
testFirstArgument([new File(["bits"], "world.txt")], 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileArrayBufferFileBits() {
|
||||||
|
testFirstArgument([new ArrayBuffer(8)], 8);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileTypedArrayFileBits() {
|
||||||
|
testFirstArgument([new Uint8Array([0x50, 0x41, 0x53, 0x53])], 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileVariousFileBits() {
|
||||||
|
testFirstArgument(
|
||||||
|
[
|
||||||
|
"bits",
|
||||||
|
new Blob(["bits"]),
|
||||||
|
new Blob(),
|
||||||
|
new Uint8Array([0x50, 0x41]),
|
||||||
|
new Uint16Array([0x5353]),
|
||||||
|
new Uint32Array([0x53534150])
|
||||||
|
],
|
||||||
|
16
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileNumberInFileBits() {
|
||||||
|
testFirstArgument([12], 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileArrayInFileBits() {
|
||||||
|
testFirstArgument([[1, 2, 3]], 5);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileObjectInFileBits() {
|
||||||
|
// "[object Object]"
|
||||||
|
testFirstArgument([{}], 15);
|
||||||
|
});
|
||||||
|
|
||||||
|
function testSecondArgument(arg2, expectedFileName) {
|
||||||
|
const file = new File(["bits"], arg2);
|
||||||
|
assert(file instanceof File);
|
||||||
|
assertEqual(file.name, expectedFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
test(function fileUsingFileName() {
|
||||||
|
testSecondArgument("dummy", "dummy");
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileUsingSpecialCharacterInFileName() {
|
||||||
|
testSecondArgument("dummy/foo", "dummy:foo");
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileUsingNullFileName() {
|
||||||
|
testSecondArgument(null, "null");
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileUsingNumberFileName() {
|
||||||
|
testSecondArgument(1, "1");
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function fileUsingEmptyStringFileName() {
|
||||||
|
testSecondArgument("", "");
|
||||||
|
});
|
107
js/form_data.ts
Normal file
107
js/form_data.ts
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
||||||
|
import * as domTypes from "./dom_types";
|
||||||
|
import * as blob from "./blob";
|
||||||
|
import * as file from "./file";
|
||||||
|
import { DomIterableMixin } from "./mixins/dom_iterable";
|
||||||
|
|
||||||
|
const dataSymbol = Symbol("data");
|
||||||
|
|
||||||
|
class FormDataBase {
|
||||||
|
private [dataSymbol]: Array<[string, domTypes.FormDataEntryValue]> = [];
|
||||||
|
|
||||||
|
/** Appends a new value onto an existing key inside a `FormData`
|
||||||
|
* object, or adds the key if it does not already exist.
|
||||||
|
*
|
||||||
|
* formData.append('name', 'first');
|
||||||
|
* formData.append('name', 'second');
|
||||||
|
*/
|
||||||
|
append(name: string, value: string): void;
|
||||||
|
append(name: string, value: blob.DenoBlob, filename?: string): void;
|
||||||
|
append(name: string, value: string | blob.DenoBlob, filename?: string): void {
|
||||||
|
if (value instanceof blob.DenoBlob) {
|
||||||
|
const dfile = new file.DenoFile([value], filename || name);
|
||||||
|
this[dataSymbol].push([name, dfile]);
|
||||||
|
} else {
|
||||||
|
this[dataSymbol].push([name, String(value)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deletes a key/value pair from a `FormData` object.
|
||||||
|
*
|
||||||
|
* formData.delete('name');
|
||||||
|
*/
|
||||||
|
delete(name: string): void {
|
||||||
|
let i = 0;
|
||||||
|
while (i < this[dataSymbol].length) {
|
||||||
|
if (this[dataSymbol][i][0] === name) {
|
||||||
|
this[dataSymbol].splice(i, 1);
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns an array of all the values associated with a given key
|
||||||
|
* from within a `FormData`.
|
||||||
|
*
|
||||||
|
* formData.getAll('name');
|
||||||
|
*/
|
||||||
|
getAll(name: string): domTypes.FormDataEntryValue[] {
|
||||||
|
const values = [];
|
||||||
|
for (const entry of this[dataSymbol]) {
|
||||||
|
if (entry[0] === name) {
|
||||||
|
values.push(entry[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the first value associated with a given key from within a
|
||||||
|
* `FormData` object.
|
||||||
|
*
|
||||||
|
* formData.get('name');
|
||||||
|
*/
|
||||||
|
get(name: string): domTypes.FormDataEntryValue | null {
|
||||||
|
for (const entry of this[dataSymbol]) {
|
||||||
|
if (entry[0] === name) {
|
||||||
|
return entry[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a boolean stating whether a `FormData` object contains a
|
||||||
|
* certain key/value pair.
|
||||||
|
*
|
||||||
|
* formData.has('name');
|
||||||
|
*/
|
||||||
|
has(name: string): boolean {
|
||||||
|
return this[dataSymbol].some(entry => entry[0] === name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets a new value for an existing key inside a `FormData` object, or
|
||||||
|
* adds the key/value if it does not already exist.
|
||||||
|
*
|
||||||
|
* formData.set('name', 'value');
|
||||||
|
*/
|
||||||
|
set(name: string, value: string): void;
|
||||||
|
set(name: string, value: blob.DenoBlob, filename?: string): void;
|
||||||
|
set(name: string, value: string | blob.DenoBlob, filename?: string): void {
|
||||||
|
this.delete(name);
|
||||||
|
if (value instanceof blob.DenoBlob) {
|
||||||
|
const dfile = new file.DenoFile([value], filename || name);
|
||||||
|
this[dataSymbol].push([name, dfile]);
|
||||||
|
} else {
|
||||||
|
this[dataSymbol].push([name, String(value)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line:variable-name
|
||||||
|
export const FormData = DomIterableMixin<
|
||||||
|
string,
|
||||||
|
domTypes.FormDataEntryValue,
|
||||||
|
typeof FormDataBase
|
||||||
|
>(FormDataBase, dataSymbol);
|
92
js/form_data_test.ts
Normal file
92
js/form_data_test.ts
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
||||||
|
import { test, assert, assertEqual } from "./test_util.ts";
|
||||||
|
|
||||||
|
test(function formDataParamsAppendSuccess() {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("a", "true");
|
||||||
|
assertEqual(formData.get("a"), "true");
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function formDataParamsDeleteSuccess() {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("a", "true");
|
||||||
|
formData.append("b", "false");
|
||||||
|
assertEqual(formData.get("b"), "false");
|
||||||
|
formData.delete("b");
|
||||||
|
assertEqual(formData.get("a"), "true");
|
||||||
|
assertEqual(formData.get("b"), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function formDataParamsGetAllSuccess() {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("a", "true");
|
||||||
|
formData.append("b", "false");
|
||||||
|
formData.append("a", "null");
|
||||||
|
assertEqual(formData.getAll("a"), ["true", "null"]);
|
||||||
|
assertEqual(formData.getAll("b"), ["false"]);
|
||||||
|
assertEqual(formData.getAll("c"), []);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function formDataParamsGetSuccess() {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("a", "true");
|
||||||
|
formData.append("b", "false");
|
||||||
|
formData.append("a", "null");
|
||||||
|
formData.append("d", undefined);
|
||||||
|
formData.append("e", null);
|
||||||
|
assertEqual(formData.get("a"), "true");
|
||||||
|
assertEqual(formData.get("b"), "false");
|
||||||
|
assertEqual(formData.get("c"), null);
|
||||||
|
assertEqual(formData.get("d"), "undefined");
|
||||||
|
assertEqual(formData.get("e"), "null");
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function formDataParamsHasSuccess() {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("a", "true");
|
||||||
|
formData.append("b", "false");
|
||||||
|
assert(formData.has("a"));
|
||||||
|
assert(formData.has("b"));
|
||||||
|
assert(!formData.has("c"));
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function formDataParamsSetSuccess() {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("a", "true");
|
||||||
|
formData.append("b", "false");
|
||||||
|
formData.append("a", "null");
|
||||||
|
assertEqual(formData.getAll("a"), ["true", "null"]);
|
||||||
|
assertEqual(formData.getAll("b"), ["false"]);
|
||||||
|
formData.set("a", "false");
|
||||||
|
assertEqual(formData.getAll("a"), ["false"]);
|
||||||
|
formData.set("d", undefined);
|
||||||
|
assertEqual(formData.get("d"), "undefined");
|
||||||
|
formData.set("e", null);
|
||||||
|
assertEqual(formData.get("e"), "null");
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function formDataSetEmptyBlobSuccess() {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.set("a", new Blob([]), "blank.txt");
|
||||||
|
const file = formData.get("a");
|
||||||
|
assert(file instanceof File);
|
||||||
|
if (typeof file !== "string") {
|
||||||
|
assertEqual(file.name, "blank.txt");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test(function formDataParamsForEachSuccess() {
|
||||||
|
const init = [["a", "54"], ["b", "true"]];
|
||||||
|
const formData = new FormData();
|
||||||
|
for (const [name, value] of init) {
|
||||||
|
formData.append(name, value);
|
||||||
|
}
|
||||||
|
let callNum = 0;
|
||||||
|
formData.forEach((value, key, parent) => {
|
||||||
|
assertEqual(formData, parent);
|
||||||
|
assertEqual(value, init[callNum][1]);
|
||||||
|
assertEqual(key, init[callNum][0]);
|
||||||
|
callNum++;
|
||||||
|
});
|
||||||
|
assertEqual(callNum, init.length);
|
||||||
|
});
|
|
@ -1,5 +1,7 @@
|
||||||
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
||||||
import * as blob from "./blob";
|
import * as blob from "./blob";
|
||||||
|
import * as file from "./file";
|
||||||
|
import * as formdata from "./form_data";
|
||||||
import * as console_ from "./console";
|
import * as console_ from "./console";
|
||||||
import * as fetch_ from "./fetch";
|
import * as fetch_ from "./fetch";
|
||||||
import { Headers } from "./headers";
|
import { Headers } from "./headers";
|
||||||
|
@ -44,3 +46,5 @@ window.fetch = fetch_.fetch;
|
||||||
// runtime library
|
// runtime library
|
||||||
window.Headers = Headers as domTypes.HeadersConstructor;
|
window.Headers = Headers as domTypes.HeadersConstructor;
|
||||||
window.Blob = blob.DenoBlob;
|
window.Blob = blob.DenoBlob;
|
||||||
|
window.File = file.DenoFile;
|
||||||
|
window.FormData = formdata.FormData as domTypes.FormDataConstructor;
|
||||||
|
|
|
@ -21,22 +21,27 @@ export function DomIterableMixin<K, V, TBase extends Constructor>(
|
||||||
// Base class in a way where the Symbol `dataSymbol` is defined. So the
|
// Base class in a way where the Symbol `dataSymbol` is defined. So the
|
||||||
// runtime code works, but we do lose a little bit of type safety.
|
// runtime code works, but we do lose a little bit of type safety.
|
||||||
|
|
||||||
|
// Additionally, we have to not use .keys() nor .values() since the internal
|
||||||
|
// slot differs in type - some have a Map, which yields [K, V] in
|
||||||
|
// Symbol.iterator, and some have an Array, which yields V, in this case
|
||||||
|
// [K, V] too as they are arrays of tuples.
|
||||||
|
|
||||||
// tslint:disable-next-line:variable-name
|
// tslint:disable-next-line:variable-name
|
||||||
const DomIterable = class extends Base {
|
const DomIterable = class extends Base {
|
||||||
*entries(): IterableIterator<[K, V]> {
|
*entries(): IterableIterator<[K, V]> {
|
||||||
for (const entry of (this as any)[dataSymbol].entries()) {
|
for (const entry of (this as any)[dataSymbol]) {
|
||||||
yield entry;
|
yield entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*keys(): IterableIterator<K> {
|
*keys(): IterableIterator<K> {
|
||||||
for (const key of (this as any)[dataSymbol].keys()) {
|
for (const [key] of (this as any)[dataSymbol]) {
|
||||||
yield key;
|
yield key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*values(): IterableIterator<V> {
|
*values(): IterableIterator<V> {
|
||||||
for (const value of (this as any)[dataSymbol].values()) {
|
for (const [, value] of (this as any)[dataSymbol]) {
|
||||||
yield value;
|
yield value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +52,7 @@ export function DomIterableMixin<K, V, TBase extends Constructor>(
|
||||||
thisArg?: any
|
thisArg?: any
|
||||||
): void {
|
): void {
|
||||||
callbackfn = callbackfn.bind(thisArg == null ? window : Object(thisArg));
|
callbackfn = callbackfn.bind(thisArg == null ? window : Object(thisArg));
|
||||||
for (const [key, value] of (this as any)[dataSymbol].entries()) {
|
for (const [key, value] of (this as any)[dataSymbol]) {
|
||||||
callbackfn(value, key, this);
|
callbackfn(value, key, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,9 @@ import "./console_test.ts";
|
||||||
import "./copy_file_test.ts";
|
import "./copy_file_test.ts";
|
||||||
import "./dir_test";
|
import "./dir_test";
|
||||||
import "./fetch_test.ts";
|
import "./fetch_test.ts";
|
||||||
|
import "./file_test.ts";
|
||||||
import "./files_test.ts";
|
import "./files_test.ts";
|
||||||
|
import "./form_data_test.ts";
|
||||||
import "./headers_test.ts";
|
import "./headers_test.ts";
|
||||||
import "./make_temp_dir_test.ts";
|
import "./make_temp_dir_test.ts";
|
||||||
import "./metrics_test.ts";
|
import "./metrics_test.ts";
|
||||||
|
|
Loading…
Reference in a new issue