From cab5117d854eca1dc0f87ec61871aec8fd1e33d4 Mon Sep 17 00:00:00 2001 From: Muki Kiboigo Date: Mon, 18 Aug 2025 15:43:22 -0700 Subject: [PATCH] remove polyfill and add req/resp --- src/browser/env.zig | 2 + src/browser/fetch/Headers.zig | 88 ++++ src/browser/fetch/Request.zig | 68 +++ src/browser/fetch/Response.zig | 0 src/browser/polyfill/fetch.js | 671 ------------------------- src/browser/polyfill/fetch.zig | 31 -- src/browser/polyfill/polyfill.zig | 21 - src/browser/streams/ReadableStream.zig | 0 8 files changed, 158 insertions(+), 723 deletions(-) create mode 100644 src/browser/fetch/Headers.zig create mode 100644 src/browser/fetch/Request.zig create mode 100644 src/browser/fetch/Response.zig delete mode 100644 src/browser/polyfill/fetch.js delete mode 100644 src/browser/polyfill/fetch.zig create mode 100644 src/browser/streams/ReadableStream.zig diff --git a/src/browser/env.zig b/src/browser/env.zig index c6f0469c..24b06ec7 100644 --- a/src/browser/env.zig +++ b/src/browser/env.zig @@ -36,6 +36,8 @@ const WebApis = struct { @import("xhr/form_data.zig").Interfaces, @import("xhr/File.zig"), @import("xmlserializer/xmlserializer.zig").Interfaces, + @import("fetch/Request.zig"), + @import("fetch/Headers.zig"), }); }; diff --git a/src/browser/fetch/Headers.zig b/src/browser/fetch/Headers.zig new file mode 100644 index 00000000..71fe52ee --- /dev/null +++ b/src/browser/fetch/Headers.zig @@ -0,0 +1,88 @@ +// Copyright (C) 2023-2024 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +const std = @import("std"); +const URL = @import("../../url.zig").URL; +const Page = @import("../page.zig").Page; + +// https://developer.mozilla.org/en-US/docs/Web/API/Headers +const Headers = @This(); + +headers: std.StringHashMapUnmanaged([]const u8), + +// They can either be: +// +// 1. An array of string pairs. +// 2. An object with string keys to string values. +// 3. Another Headers object. +const HeadersInit = union(enum) { + strings: []const []const u8, + // headers: Headers, +}; + +pub fn constructor(_init: ?[]const HeadersInit, page: *Page) !Headers { + const arena = page.arena; + var headers = std.StringHashMapUnmanaged([]const u8).empty; + + if (_init) |init| { + for (init) |item| { + switch (item) { + .strings => |pair| { + // Can only have two string elements if in a pair. + if (pair.len != 2) { + return error.TypeError; + } + + const raw_key = pair[0]; + const value = pair[1]; + const key = try std.ascii.allocLowerString(arena, raw_key); + + try headers.put(arena, key, value); + }, + // .headers => |_| {}, + } + } + } + + return .{ + .headers = headers, + }; +} + +pub fn _get(self: *const Headers, header: []const u8, page: *Page) !?[]const u8 { + const arena = page.arena; + const key = try std.ascii.allocLowerString(arena, header); + + const value = (self.headers.getEntry(key) orelse return null).value_ptr.*; + return try arena.dupe(u8, value); +} + +const testing = @import("../../testing.zig"); +test "fetch: headers" { + var runner = try testing.jsRunner(testing.tracking_allocator, .{ .url = "https://lightpanda.io" }); + defer runner.deinit(); + + try runner.testCases(&.{ + .{ "let empty_headers = new Headers()", "undefined" }, + }, .{}); + + try runner.testCases(&.{ + .{ "let headers = new Headers([['Set-Cookie', 'name=world']])", "undefined" }, + .{ "headers.get('set-cookie')", "name=world" }, + }, .{}); +} diff --git a/src/browser/fetch/Request.zig b/src/browser/fetch/Request.zig new file mode 100644 index 00000000..90f3d0ad --- /dev/null +++ b/src/browser/fetch/Request.zig @@ -0,0 +1,68 @@ +// Copyright (C) 2023-2024 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +const std = @import("std"); +const URL = @import("../../url.zig").URL; +const Page = @import("../page.zig").Page; + +// https://developer.mozilla.org/en-US/docs/Web/API/Request/Request +const Request = @This(); + +url: []const u8, + +const RequestInput = union(enum) { + string: []const u8, + request: Request, +}; + +pub fn constructor(input: RequestInput, page: *Page) !Request { + const arena = page.arena; + + const url = blk: switch (input) { + .string => |str| { + break :blk try URL.stitch(arena, str, page.url.raw, .{}); + }, + .request => |req| { + break :blk try arena.dupe(u8, req.url); + }, + }; + + return .{ + .url = url, + }; +} + +pub fn get_url(self: *const Request, page: *Page) ![]const u8 { + return try page.arena.dupe(u8, self.url); +} + +const testing = @import("../../testing.zig"); +test "fetch: request" { + var runner = try testing.jsRunner(testing.tracking_allocator, .{ .url = "https://lightpanda.io" }); + defer runner.deinit(); + + try runner.testCases(&.{ + .{ "let request = new Request('flower.png')", "undefined" }, + .{ "request.url", "https://lightpanda.io/flower.png" }, + }, .{}); + + try runner.testCases(&.{ + .{ "let request2 = new Request('https://google.com')", "undefined" }, + .{ "request2.url", "https://google.com" }, + }, .{}); +} diff --git a/src/browser/fetch/Response.zig b/src/browser/fetch/Response.zig new file mode 100644 index 00000000..e69de29b diff --git a/src/browser/polyfill/fetch.js b/src/browser/polyfill/fetch.js deleted file mode 100644 index 75efab54..00000000 --- a/src/browser/polyfill/fetch.js +++ /dev/null @@ -1,671 +0,0 @@ -// fetch.js code comes from -// https://github.com/JakeChampion/fetch/blob/main/fetch.js -// -// The original code source is available in MIT license. -// -// The script comes from the built version from npm. -// You can get the package with the command: -// -// wget $(npm view whatwg-fetch dist.tarball) -// -// The source is the content of `package/dist/fetch.umd.js` file. -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define(['exports'], factory) : - (factory((global.WHATWGFetch = {}))); -}(this, (function (exports) { 'use strict'; - - /* eslint-disable no-prototype-builtins */ - var g = - (typeof globalThis !== 'undefined' && globalThis) || - (typeof self !== 'undefined' && self) || - // eslint-disable-next-line no-undef - (typeof global !== 'undefined' && global) || - {}; - - var support = { - searchParams: 'URLSearchParams' in g, - iterable: 'Symbol' in g && 'iterator' in Symbol, - blob: - 'FileReader' in g && - 'Blob' in g && - (function() { - try { - new Blob(); - return true - } catch (e) { - return false - } - })(), - formData: 'FormData' in g, - - // Arraybuffer is available but xhr doesn't implement it for now. - // arrayBuffer: 'ArrayBuffer' in g - arrayBuffer: false - }; - - function isDataView(obj) { - return obj && DataView.prototype.isPrototypeOf(obj) - } - - if (support.arrayBuffer) { - var viewClasses = [ - '[object Int8Array]', - '[object Uint8Array]', - '[object Uint8ClampedArray]', - '[object Int16Array]', - '[object Uint16Array]', - '[object Int32Array]', - '[object Uint32Array]', - '[object Float32Array]', - '[object Float64Array]' - ]; - - var isArrayBufferView = - ArrayBuffer.isView || - function(obj) { - return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1 - }; - } - - function normalizeName(name) { - if (typeof name !== 'string') { - name = String(name); - } - if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === '') { - throw new TypeError('Invalid character in header field name: "' + name + '"') - } - return name.toLowerCase() - } - - function normalizeValue(value) { - if (typeof value !== 'string') { - value = String(value); - } - return value - } - - // Build a destructive iterator for the value list - function iteratorFor(items) { - var iterator = { - next: function() { - var value = items.shift(); - return {done: value === undefined, value: value} - } - }; - - if (support.iterable) { - iterator[Symbol.iterator] = function() { - return iterator - }; - } - - return iterator - } - - function Headers(headers) { - this.map = {}; - - if (headers instanceof Headers) { - headers.forEach(function(value, name) { - this.append(name, value); - }, this); - } else if (Array.isArray(headers)) { - headers.forEach(function(header) { - if (header.length != 2) { - throw new TypeError('Headers constructor: expected name/value pair to be length 2, found' + header.length) - } - this.append(header[0], header[1]); - }, this); - } else if (headers) { - Object.getOwnPropertyNames(headers).forEach(function(name) { - this.append(name, headers[name]); - }, this); - } - } - - Headers.prototype.append = function(name, value) { - name = normalizeName(name); - value = normalizeValue(value); - var oldValue = this.map[name]; - this.map[name] = oldValue ? oldValue + ', ' + value : value; - }; - - Headers.prototype['delete'] = function(name) { - delete this.map[normalizeName(name)]; - }; - - Headers.prototype.get = function(name) { - name = normalizeName(name); - return this.has(name) ? this.map[name] : null - }; - - Headers.prototype.has = function(name) { - return this.map.hasOwnProperty(normalizeName(name)) - }; - - Headers.prototype.set = function(name, value) { - this.map[normalizeName(name)] = normalizeValue(value); - }; - - Headers.prototype.forEach = function(callback, thisArg) { - for (var name in this.map) { - if (this.map.hasOwnProperty(name)) { - callback.call(thisArg, this.map[name], name, this); - } - } - }; - - Headers.prototype.keys = function() { - var items = []; - this.forEach(function(value, name) { - items.push(name); - }); - return iteratorFor(items) - }; - - Headers.prototype.values = function() { - var items = []; - this.forEach(function(value) { - items.push(value); - }); - return iteratorFor(items) - }; - - Headers.prototype.entries = function() { - var items = []; - this.forEach(function(value, name) { - items.push([name, value]); - }); - return iteratorFor(items) - }; - - if (support.iterable) { - Headers.prototype[Symbol.iterator] = Headers.prototype.entries; - } - - function consumed(body) { - if (body._noBody) return - if (body.bodyUsed) { - return Promise.reject(new TypeError('Already read')) - } - body.bodyUsed = true; - } - - function fileReaderReady(reader) { - return new Promise(function(resolve, reject) { - reader.onload = function() { - resolve(reader.result); - }; - reader.onerror = function() { - reject(reader.error); - }; - }) - } - - function readBlobAsArrayBuffer(blob) { - var reader = new FileReader(); - var promise = fileReaderReady(reader); - reader.readAsArrayBuffer(blob); - return promise - } - - function readBlobAsText(blob) { - var reader = new FileReader(); - var promise = fileReaderReady(reader); - var match = /charset=([A-Za-z0-9_-]+)/.exec(blob.type); - var encoding = match ? match[1] : 'utf-8'; - reader.readAsText(blob, encoding); - return promise - } - - function readArrayBufferAsText(buf) { - var view = new Uint8Array(buf); - var chars = new Array(view.length); - - for (var i = 0; i < view.length; i++) { - chars[i] = String.fromCharCode(view[i]); - } - return chars.join('') - } - - function bufferClone(buf) { - if (buf.slice) { - return buf.slice(0) - } else { - var view = new Uint8Array(buf.byteLength); - view.set(new Uint8Array(buf)); - return view.buffer - } - } - - function Body() { - this.bodyUsed = false; - - this._initBody = function(body) { - /* - fetch-mock wraps the Response object in an ES6 Proxy to - provide useful test harness features such as flush. However, on - ES5 browsers without fetch or Proxy support pollyfills must be used; - the proxy-pollyfill is unable to proxy an attribute unless it exists - on the object before the Proxy is created. This change ensures - Response.bodyUsed exists on the instance, while maintaining the - semantic of setting Request.bodyUsed in the constructor before - _initBody is called. - */ - // eslint-disable-next-line no-self-assign - this.bodyUsed = this.bodyUsed; - this._bodyInit = body; - if (!body) { - this._noBody = true; - this._bodyText = ''; - } else if (typeof body === 'string') { - this._bodyText = body; - } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { - this._bodyBlob = body; - } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { - this._bodyFormData = body; - } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { - this._bodyText = body.toString(); - } else if (support.arrayBuffer && support.blob && isDataView(body)) { - this._bodyArrayBuffer = bufferClone(body.buffer); - // IE 10-11 can't handle a DataView body. - this._bodyInit = new Blob([this._bodyArrayBuffer]); - } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) { - this._bodyArrayBuffer = bufferClone(body); - } else { - this._bodyText = body = Object.prototype.toString.call(body); - } - - if (!this.headers.get('content-type')) { - if (typeof body === 'string') { - this.headers.set('content-type', 'text/plain;charset=UTF-8'); - } else if (this._bodyBlob && this._bodyBlob.type) { - this.headers.set('content-type', this._bodyBlob.type); - } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { - this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8'); - } - } - }; - - if (support.blob) { - this.blob = function() { - var rejected = consumed(this); - if (rejected) { - return rejected - } - - if (this._bodyBlob) { - return Promise.resolve(this._bodyBlob) - } else if (this._bodyArrayBuffer) { - return Promise.resolve(new Blob([this._bodyArrayBuffer])) - } else if (this._bodyFormData) { - throw new Error('could not read FormData body as blob') - } else { - return Promise.resolve(new Blob([this._bodyText])) - } - }; - } - - this.arrayBuffer = function() { - if (this._bodyArrayBuffer) { - var isConsumed = consumed(this); - if (isConsumed) { - return isConsumed - } else if (ArrayBuffer.isView(this._bodyArrayBuffer)) { - return Promise.resolve( - this._bodyArrayBuffer.buffer.slice( - this._bodyArrayBuffer.byteOffset, - this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength - ) - ) - } else { - return Promise.resolve(this._bodyArrayBuffer) - } - } else if (support.blob) { - return this.blob().then(readBlobAsArrayBuffer) - } else { - throw new Error('could not read as ArrayBuffer') - } - }; - - this.text = function() { - var rejected = consumed(this); - if (rejected) { - return rejected - } - - if (this._bodyBlob) { - return readBlobAsText(this._bodyBlob) - } else if (this._bodyArrayBuffer) { - return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer)) - } else if (this._bodyFormData) { - throw new Error('could not read FormData body as text') - } else { - return Promise.resolve(this._bodyText) - } - }; - - if (support.formData) { - this.formData = function() { - return this.text().then(decode) - }; - } - - this.json = function() { - return this.text().then(JSON.parse) - }; - - return this - } - - // HTTP methods whose capitalization should be normalized - var methods = ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE']; - - function normalizeMethod(method) { - var upcased = method.toUpperCase(); - return methods.indexOf(upcased) > -1 ? upcased : method - } - - function Request(input, options) { - if (!(this instanceof Request)) { - throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.') - } - - options = options || {}; - var body = options.body; - - if (input instanceof Request) { - if (input.bodyUsed) { - throw new TypeError('Already read') - } - this.url = input.url; - this.credentials = input.credentials; - if (!options.headers) { - this.headers = new Headers(input.headers); - } - this.method = input.method; - this.mode = input.mode; - this.signal = input.signal; - if (!body && input._bodyInit != null) { - body = input._bodyInit; - input.bodyUsed = true; - } - } else { - this.url = String(input); - } - - this.credentials = options.credentials || this.credentials || 'same-origin'; - if (options.headers || !this.headers) { - this.headers = new Headers(options.headers); - } - this.method = normalizeMethod(options.method || this.method || 'GET'); - this.mode = options.mode || this.mode || null; - this.signal = options.signal || this.signal || (function () { - if ('AbortController' in g) { - var ctrl = new AbortController(); - return ctrl.signal; - } - }()); - this.referrer = null; - - if ((this.method === 'GET' || this.method === 'HEAD') && body) { - throw new TypeError('Body not allowed for GET or HEAD requests') - } - this._initBody(body); - - if (this.method === 'GET' || this.method === 'HEAD') { - if (options.cache === 'no-store' || options.cache === 'no-cache') { - // Search for a '_' parameter in the query string - var reParamSearch = /([?&])_=[^&]*/; - if (reParamSearch.test(this.url)) { - // If it already exists then set the value with the current time - this.url = this.url.replace(reParamSearch, '$1_=' + new Date().getTime()); - } else { - // Otherwise add a new '_' parameter to the end with the current time - var reQueryString = /\?/; - this.url += (reQueryString.test(this.url) ? '&' : '?') + '_=' + new Date().getTime(); - } - } - } - } - - Request.prototype.clone = function() { - return new Request(this, {body: this._bodyInit}) - }; - - function decode(body) { - var form = new FormData(); - body - .trim() - .split('&') - .forEach(function(bytes) { - if (bytes) { - var split = bytes.split('='); - var name = split.shift().replace(/\+/g, ' '); - var value = split.join('=').replace(/\+/g, ' '); - form.append(decodeURIComponent(name), decodeURIComponent(value)); - } - }); - return form - } - - function parseHeaders(rawHeaders) { - var headers = new Headers(); - // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space - // https://tools.ietf.org/html/rfc7230#section-3.2 - var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' '); - // Avoiding split via regex to work around a common IE11 bug with the core-js 3.6.0 regex polyfill - // https://github.com/github/fetch/issues/748 - // https://github.com/zloirock/core-js/issues/751 - preProcessedHeaders - .split('\r') - .map(function(header) { - return header.indexOf('\n') === 0 ? header.substr(1, header.length) : header - }) - .forEach(function(line) { - var parts = line.split(':'); - var key = parts.shift().trim(); - if (key) { - var value = parts.join(':').trim(); - try { - headers.append(key, value); - } catch (error) { - console.warn('Response ' + error.message); - } - } - }); - return headers - } - - Body.call(Request.prototype); - - function Response(bodyInit, options) { - if (!(this instanceof Response)) { - throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.') - } - if (!options) { - options = {}; - } - - this.type = 'default'; - this.status = options.status === undefined ? 200 : options.status; - if (this.status < 200 || this.status > 599) { - throw new RangeError("Failed to construct 'Response': The status provided (0) is outside the range [200, 599].") - } - this.ok = this.status >= 200 && this.status < 300; - this.statusText = options.statusText === undefined ? '' : '' + options.statusText; - this.headers = new Headers(options.headers); - this.url = options.url || ''; - this._initBody(bodyInit); - } - - Body.call(Response.prototype); - - Response.prototype.clone = function() { - return new Response(this._bodyInit, { - status: this.status, - statusText: this.statusText, - headers: new Headers(this.headers), - url: this.url - }) - }; - - Response.error = function() { - var response = new Response(null, {status: 200, statusText: ''}); - response.ok = false; - response.status = 0; - response.type = 'error'; - return response - }; - - var redirectStatuses = [301, 302, 303, 307, 308]; - - Response.redirect = function(url, status) { - if (redirectStatuses.indexOf(status) === -1) { - throw new RangeError('Invalid status code') - } - - return new Response(null, {status: status, headers: {location: url}}) - }; - - exports.DOMException = g.DOMException; - try { - new exports.DOMException(); - } catch (err) { - exports.DOMException = function(message, name) { - this.message = message; - this.name = name; - var error = Error(message); - this.stack = error.stack; - }; - exports.DOMException.prototype = Object.create(Error.prototype); - exports.DOMException.prototype.constructor = exports.DOMException; - } - - function fetch(input, init) { - return new Promise(function(resolve, reject) { - var request = new Request(input, init); - - if (request.signal && request.signal.aborted) { - return reject(new exports.DOMException('Aborted', 'AbortError')) - } - - var xhr = new XMLHttpRequest(); - - function abortXhr() { - xhr.abort(); - } - - xhr.onload = function() { - var options = { - statusText: xhr.statusText, - headers: parseHeaders(xhr.getAllResponseHeaders() || '') - }; - // This check if specifically for when a user fetches a file locally from the file system - // Only if the status is out of a normal range - if (request.url.indexOf('file://') === 0 && (xhr.status < 200 || xhr.status > 599)) { - options.status = 200; - } else { - options.status = xhr.status; - } - options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL'); - var body = 'response' in xhr ? xhr.response : xhr.responseText; - setTimeout(function() { - resolve(new Response(body, options)); - }, 0); - }; - - xhr.onerror = function() { - setTimeout(function() { - reject(new TypeError('Network request failed')); - }, 0); - }; - - xhr.ontimeout = function() { - setTimeout(function() { - reject(new TypeError('Network request timed out')); - }, 0); - }; - - xhr.onabort = function() { - setTimeout(function() { - reject(new exports.DOMException('Aborted', 'AbortError')); - }, 0); - }; - - function fixUrl(url) { - try { - return url === '' && g.location.href ? g.location.href : url - } catch (e) { - return url - } - } - - xhr.open(request.method, fixUrl(request.url), true); - - if (request.credentials === 'include') { - xhr.withCredentials = true; - } else if (request.credentials === 'omit') { - xhr.withCredentials = false; - } - - if ('responseType' in xhr) { - if (support.blob) { - xhr.responseType = 'blob'; - } else if ( - support.arrayBuffer - ) { - xhr.responseType = 'arraybuffer'; - } - } - - if (init && typeof init.headers === 'object' && !(init.headers instanceof Headers || (g.Headers && init.headers instanceof g.Headers))) { - var names = []; - Object.getOwnPropertyNames(init.headers).forEach(function(name) { - names.push(normalizeName(name)); - xhr.setRequestHeader(name, normalizeValue(init.headers[name])); - }); - request.headers.forEach(function(value, name) { - if (names.indexOf(name) === -1) { - xhr.setRequestHeader(name, value); - } - }); - } else { - request.headers.forEach(function(value, name) { - xhr.setRequestHeader(name, value); - }); - } - - if (request.signal) { - request.signal.addEventListener('abort', abortXhr); - - xhr.onreadystatechange = function() { - // DONE (success or failure) - if (xhr.readyState === 4) { - request.signal.removeEventListener('abort', abortXhr); - } - }; - } - - xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit); - }) - } - - fetch.polyfill = true; - - if (!g.fetch) { - g.fetch = fetch; - g.Headers = Headers; - g.Request = Request; - g.Response = Response; - } - - exports.Headers = Headers; - exports.Request = Request; - exports.Response = Response; - exports.fetch = fetch; - - Object.defineProperty(exports, '__esModule', { value: true }); - -}))); diff --git a/src/browser/polyfill/fetch.zig b/src/browser/polyfill/fetch.zig deleted file mode 100644 index 9ed134de..00000000 --- a/src/browser/polyfill/fetch.zig +++ /dev/null @@ -1,31 +0,0 @@ -// fetch.js code comes from -// https://github.com/JakeChampion/fetch/blob/main/fetch.js -// -// The original code source is available in MIT license. -// -// The script comes from the built version from npm. -// You can get the package with the command: -// -// wget $(npm view whatwg-fetch dist.tarball) -// -// The source is the content of `package/dist/fetch.umd.js` file. -pub const source = @embedFile("fetch.js"); - -const testing = @import("../../testing.zig"); -test "Browser.fetch" { - var runner = try testing.jsRunner(testing.tracking_allocator, .{}); - defer runner.deinit(); - - try runner.testCases(&.{ - .{ - \\ var ok = false; - \\ const request = new Request("http://127.0.0.1:9582/loader"); - \\ fetch(request).then((response) => { ok = response.ok; }); - \\ false; - , - "false", - }, - // all events have been resolved. - .{ "ok", "true" }, - }, .{}); -} diff --git a/src/browser/polyfill/polyfill.zig b/src/browser/polyfill/polyfill.zig index 59822c62..617bdf86 100644 --- a/src/browser/polyfill/polyfill.zig +++ b/src/browser/polyfill/polyfill.zig @@ -27,7 +27,6 @@ pub const Loader = struct { state: enum { empty, loading } = .empty, done: struct { - fetch: bool = false, webcomponents: bool = false, } = .{}, @@ -56,18 +55,6 @@ pub const Loader = struct { return false; } - if (!self.done.fetch and isFetch(name)) { - const source = @import("fetch.zig").source; - self.load("fetch", source, js_context); - - // We return false here: We want v8 to continue the calling chain - // to finally find the polyfill we just inserted. If we want to - // return false and stops the call chain, we have to use - // `info.GetReturnValue.Set()` function, or `undefined` will be - // returned immediately. - return false; - } - if (!self.done.webcomponents and isWebcomponents(name)) { const source = @import("webcomponents.zig").source; self.load("webcomponents", source, js_context); @@ -89,14 +76,6 @@ pub const Loader = struct { return false; } - fn isFetch(name: []const u8) bool { - if (std.mem.eql(u8, name, "fetch")) return true; - if (std.mem.eql(u8, name, "Request")) return true; - if (std.mem.eql(u8, name, "Response")) return true; - if (std.mem.eql(u8, name, "Headers")) return true; - return false; - } - fn isWebcomponents(name: []const u8) bool { if (std.mem.eql(u8, name, "customElements")) return true; return false; diff --git a/src/browser/streams/ReadableStream.zig b/src/browser/streams/ReadableStream.zig new file mode 100644 index 00000000..e69de29b