Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: update deno_file to use deno_webidl #10042

Merged
merged 4 commits into from
Apr 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 126 additions & 62 deletions op_crates/file/01_file.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// @ts-check
/// <reference no-default-lib="true" />
/// <reference path="../../core/lib.deno_core.d.ts" />
/// <reference path="../webidl/internal.d.ts" />
/// <reference path="../web/internal.d.ts" />
/// <reference path="../web/lib.deno_web.d.ts" />
/// <reference path="./internal.d.ts" />
Expand All @@ -11,6 +12,8 @@
"use strict";

((window) => {
const webidl = window.__bootstrap.webidl;

// TODO(lucacasonato): this needs to not be hardcoded and instead depend on
// host os.
const isWindows = false;
Expand Down Expand Up @@ -143,62 +146,39 @@
[_byteSequence];

/**
* @param {BlobPart[]} [blobParts]
* @param {BlobPropertyBag} [options]
* @param {BlobPart[]} blobParts
* @param {BlobPropertyBag} options
*/
constructor(blobParts, options) {
if (blobParts === undefined) {
blobParts = [];
}
if (typeof blobParts !== "object") {
throw new TypeError(
`Failed to construct 'Blob'. blobParts cannot be converted to a sequence.`,
);
}

const parts = [];
const iterator = blobParts[Symbol.iterator]?.();
if (iterator === undefined) {
throw new TypeError(
"Failed to construct 'Blob'. The provided value cannot be converted to a sequence",
);
}
while (true) {
const { value: element, done } = iterator.next();
if (done) break;
if (
ArrayBuffer.isView(element) || element instanceof ArrayBuffer ||
element instanceof Blob
) {
parts.push(element);
} else {
parts.push(String(element));
}
}
constructor(blobParts = [], options = {}) {
const prefix = "Failed to construct 'Blob'";
blobParts = webidl.converters["sequence<BlobPart>"](blobParts, {
context: "Argument 1",
prefix,
});
options = webidl.converters["BlobPropertyBag"](options, {
context: "Argument 2",
prefix,
});

if (!options || typeof options === "function") {
options = {};
}
if (typeof options !== "object") {
throw new TypeError(
`Failed to construct 'Blob'. options is not an object.`,
);
}
const endings = options.endings?.toString() ?? "transparent";
const type = options.type?.toString() ?? "";
this[webidl.brand] = webidl.brand;

/** @type {Uint8Array} */
this[_byteSequence] = processBlobParts(parts, endings);
this.#type = normalizeType(type);
this[_byteSequence] = processBlobParts(
blobParts,
options.endings,
);
this.#type = normalizeType(options.type);
}

/** @returns {number} */
get size() {
webidl.assertBranded(this, Blob);
return this[_byteSequence].byteLength;
}

/** @returns {string} */
get type() {
webidl.assertBranded(this, Blob);
return this.#type;
}

Expand All @@ -209,13 +189,35 @@
* @returns {Blob}
*/
slice(start, end, contentType) {
webidl.assertBranded(this, Blob);
const prefix = "Failed to execute 'slice' on 'Blob'";
if (start !== undefined) {
start = webidl.converters["long long"](start, {
clamp: true,
context: "Argument 1",
prefix,
});
}
if (end !== undefined) {
end = webidl.converters["long long"](end, {
clamp: true,
context: "Argument 2",
prefix,
});
}
if (contentType !== undefined) {
contentType = webidl.converters["DOMString"](contentType, {
context: "Argument 3",
prefix,
});
}

const O = this;
/** @type {number} */
let relativeStart;
if (start === undefined) {
relativeStart = 0;
} else {
start = Number(start);
if (start < 0) {
relativeStart = Math.max(O.size + start, 0);
} else {
Expand All @@ -227,7 +229,6 @@
if (end === undefined) {
relativeEnd = O.size;
} else {
end = Number(end);
if (end < 0) {
relativeEnd = Math.max(O.size + end, 0);
} else {
Expand All @@ -239,7 +240,7 @@
if (contentType === undefined) {
relativeContentType = "";
} else {
relativeContentType = normalizeType(String(contentType));
relativeContentType = normalizeType(contentType);
}
return new Blob([
O[_byteSequence].buffer.slice(relativeStart, relativeEnd),
Expand All @@ -250,6 +251,7 @@
* @returns {ReadableStream<Uint8Array>}
*/
stream() {
webidl.assertBranded(this, Blob);
const bytes = this[_byteSequence];
const stream = new ReadableStream({
type: "bytes",
Expand All @@ -267,6 +269,7 @@
* @returns {Promise<string>}
*/
async text() {
webidl.assertBranded(this, Blob);
const buffer = await this.arrayBuffer();
return utf8Decoder.decode(buffer);
}
Expand All @@ -275,6 +278,7 @@
* @returns {Promise<ArrayBuffer>}
*/
async arrayBuffer() {
webidl.assertBranded(this, Blob);
const stream = this.stream();
let bytes = new Uint8Array();
for await (const chunk of stream) {
Expand All @@ -288,6 +292,46 @@
}
}

webidl.converters["Blob"] = webidl.createInterfaceConverter("Blob", Blob);
webidl.converters["BlobPart"] = (V, opts) => {
// Union for ((ArrayBuffer or ArrayBufferView) or Blob or USVString)
if (typeof V == "object") {
if (V instanceof Blob) {
return webidl.converters["Blob"](V, opts);
}
if (V instanceof ArrayBuffer || V instanceof SharedArrayBuffer) {
return webidl.converters["ArrayBuffer"](V, opts);
}
if (ArrayBuffer.isView(V)) {
return webidl.converters["ArrayBufferView"](V, opts);
}
}
return webidl.converters["USVString"](V, opts);
};
webidl.converters["sequence<BlobPart>"] = webidl.createSequenceConverter(
webidl.converters["BlobPart"],
);
webidl.converters["EndingType"] = webidl.createEnumConverter("EndingType", [
"transparent",
"native",
]);
const blobPropertyBagDictionary = [
{
key: "type",
converter: webidl.converters["DOMString"],
defaultValue: "",
},
{
key: "endings",
converter: webidl.converters["EndingType"],
defaultValue: "transparent",
},
];
webidl.converters["BlobPropertyBag"] = webidl.createDictionaryConverter(
"BlobPropertyBag",
blobPropertyBagDictionary,
);

const _Name = Symbol("[[Name]]");
const _LastModfied = Symbol("[[LastModified]]");

Expand All @@ -300,42 +344,62 @@
/**
* @param {BlobPart[]} fileBits
* @param {string} fileName
* @param {FilePropertyBag} [options]
* @param {FilePropertyBag} options
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param {FilePropertyBag} options
* @param {FilePropertyBag=} options

Copy link
Member Author

@lucacasonato lucacasonato Apr 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Results in options is possibly undefined, which is wrong.

*/
constructor(fileBits, fileName, options) {
if (fileBits === undefined) {
throw new TypeError(
"Failed to construct 'File'. 2 arguments required, but first not specified.",
);
}
if (fileName === undefined) {
throw new TypeError(
"Failed to construct 'File'. 2 arguments required, but second not specified.",
);
}
super(fileBits, { endings: options?.endings, type: options?.type });
constructor(fileBits, fileName, options = {}) {
const prefix = "Failed to construct 'File'";
webidl.requiredArguments(arguments.length, 2, { prefix });

fileBits = webidl.converters["sequence<BlobPart>"](fileBits, {
context: "Argument 1",
prefix,
});
fileName = webidl.converters["USVString"](fileName, {
context: "Argument 2",
prefix,
});
options = webidl.converters["FilePropertyBag"](options, {
context: "Argument 3",
prefix,
});

super(fileBits, options);

/** @type {string} */
this[_Name] = String(fileName).replaceAll("/", ":");
if (options?.lastModified === undefined) {
this[_Name] = fileName.replaceAll("/", ":");
if (options.lastModified === undefined) {
/** @type {number} */
this[_LastModfied] = new Date().getTime();
} else {
/** @type {number} */
this[_LastModfied] = Number(options.lastModified);
this[_LastModfied] = options.lastModified;
}
}

/** @returns {string} */
get name() {
webidl.assertBranded(this, File);
return this[_Name];
}

/** @returns {number} */
get lastModified() {
webidl.assertBranded(this, File);
return this[_LastModfied];
}
}

webidl.converters["FilePropertyBag"] = webidl.createDictionaryConverter(
"FilePropertyBag",
blobPropertyBagDictionary,
[
{
key: "lastModified",
converter: webidl.converters["long long"],
},
],
);

window.__bootstrap.file = {
Blob,
_byteSequence,
Expand Down
26 changes: 13 additions & 13 deletions op_crates/file/03_blob_url.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

((window) => {
const core = Deno.core;
// const webidl = window.__bootstrap.webidl;
const webidl = window.__bootstrap.webidl;
const { _byteSequence } = window.__bootstrap.file;
const { URL } = window.__bootstrap.url;

Expand All @@ -24,12 +24,12 @@
* @returns {string}
*/
function createObjectURL(blob) {
// const prefix = "Failed to execute 'createObjectURL' on 'URL'";
// webidl.requiredArguments(arguments.length, 1, { prefix });
// blob = webidl.converters["Blob"](blob, {
// context: "Argument 1",
// prefix,
// });
const prefix = "Failed to execute 'createObjectURL' on 'URL'";
webidl.requiredArguments(arguments.length, 1, { prefix });
blob = webidl.converters["Blob"](blob, {
context: "Argument 1",
prefix,
});

const url = core.jsonOpSync(
"op_file_create_object_url",
Expand All @@ -45,12 +45,12 @@
* @returns {void}
*/
function revokeObjectURL(url) {
// const prefix = "Failed to execute 'revokeObjectURL' on 'URL'";
// webidl.requiredArguments(arguments.length, 1, { prefix });
// url = webidl.converters["DOMString"](url, {
// context: "Argument 1",
// prefix,
// });
const prefix = "Failed to execute 'revokeObjectURL' on 'URL'";
webidl.requiredArguments(arguments.length, 1, { prefix });
url = webidl.converters["DOMString"](url, {
context: "Argument 1",
prefix,
});

core.jsonOpSync(
"op_file_revoke_object_url",
Expand Down
Loading