Skip to content
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
2 changes: 1 addition & 1 deletion examples/atob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ const validBase64 = "YQ==";
console.log("validBase64: ", atob(validBase64)); // "a"

const validBase64Multiple = "SGVsbG8sIEFuZHJvbWVkYSE=";
console.log("validBase64Multiple: ", atob(validBase64Multiple)); // "Hello, Andromeda!"
console.log("validBase64Multiple: ", atob(validBase64Multiple)); // "Hello, Andromeda!"
15 changes: 15 additions & 0 deletions examples/headers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const httpHeaders = {
"Content-Type": "image/jpeg",
"X-My-Custom-Header": "Zeke are cool",
};
const myHeaders = new Headers(httpHeaders);
console.log("myHeaders", myHeaders.get("Content-Type")); // image/jpeg
console.log("myHeaders", myHeaders.get("X-My-Custom-Header")); // Zeke are cool

const headers2 = [
["Set-Cookie", "greeting=hello"],
["Set-Cookie", "name=world"],
];
const myHeaders2 = new Headers(headers2);
console.log("myHeaders2", myHeaders2); // TODO Headers { 'Set-Cookie': 'greeting=hello, name=world' } but [object Object]
console.log("myHeaders", myHeaders2.get("Set-Cookie")); // greeting=hellogreeting=hello,name=worldname=world
8 changes: 4 additions & 4 deletions examples/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
const baseUrl = "https://developer.mozilla.org";

const A = new URL("/", baseUrl); // 'https://developer.mozilla.org/'
console.log(A)
console.log(A);

const B = new URL(baseUrl); // 'https://developer.mozilla.org/'
console.log(B)
console.log(B);

console.log(new URL("en-US/docs", B)); // 'https://developer.mozilla.org/en-US/docs'

const D = new URL("/en-US/docs", B); // 'https://developer.mozilla.org/en-US/docs'
console.log(D)
console.log(D);

console.log(new URL("/en-US/docs", D)); // 'https://developer.mozilla.org/en-US/docs'

Expand Down Expand Up @@ -50,4 +50,4 @@ if ("parse" in URL) {
// console.log(`[5]: ${result}`);
} else {
console.log("URL.parse() not supported");
}
}
12 changes: 6 additions & 6 deletions namespace/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,20 +298,20 @@ function alert(message: string) {
}

/**
* Takes the input data, in the form of a Unicode string containing only characters in the range U+0000 to U+00FF,
* each representing a binary byte with values 0x00 to 0xFF respectively, and converts it to its base64 representation,
* Takes the input data, in the form of a Unicode string containing only characters in the range U+0000 to U+00FF,
* each representing a binary byte with values 0x00 to 0xFF respectively, and converts it to its base64 representation,
* which it returns.
*/
function btoa(input: string): string {
return internal_btoa(input);
}

/**
* Takes the input data, in the form of a Unicode string containing base64-encoded binary data,
* decodes it, and returns a string consisting of characters in the range U+0000 to U+00FF,
* each representing a binary byte with values 0x00 to 0xFF respectively,
* Takes the input data, in the form of a Unicode string containing base64-encoded binary data,
* decodes it, and returns a string consisting of characters in the range U+0000 to U+00FF,
* each representing a binary byte with values 0x00 to 0xFF respectively,
* corresponding to that binary data.
*/
function atob(input: string): string {
return internal_atob(input);
}
}
15 changes: 15 additions & 0 deletions runtime/src/ext/fetch/headers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use andromeda_core::Extension;

#[derive(Default)]
pub struct HeadersExt;

impl HeadersExt {
pub fn new_extension() -> Extension {
Extension {
name: "headers",
ops: vec![],
storage: None,
files: vec![include_str!("./mod.ts")],
}
}
}
125 changes: 125 additions & 0 deletions runtime/src/ext/fetch/headers/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
class Headers {
// TODO: Private properties
// #guard
// #headerList

// TODO: this is HeaderList type
// https://fetch.spec.whatwg.org/#headers-class
constructor(init = undefined) {
// @ts-ignore
this.guard = "none";
// @ts-ignore
this.headerList = [];
fillHeaders(this, init);
}

// https://fetch.spec.whatwg.org/#dom-headers-get
get(name: string) {
// @ts-ignore
return getHeader(this.headerList, name);
}
}

function fillHeaders(headers: Headers, object) {
if (Array.isArray(object)) {
for (let i = 0; i < object.length; ++i) {
const header = object[i];
if (header.length !== 2) {
throw new TypeError(
`Invalid header: length must be 2, but is ${header.length}`,
);
}
appendHeader(headers, header[0], header[1]);
}
} else {
for (const key in object) {
if (!Object.hasOwn(object, key)) {
continue;
}
appendHeader(headers, key, object[key]);
}
}
}

function byteLowerCase(s) {
// NOTE: correct since all callers convert to ByteString first
// TODO(@AaronO): maybe prefer a ByteString_Lower webidl converter
return s;
}

// https://fetch.spec.whatwg.org/#concept-headers-append
function appendHeader(headers, name, value) {
// 1.
value = normalizeHeaderValue(value);

// 2. TODO
// if (!checkHeaderNameForHttpTokenCodePoint(name)) {
// throw new TypeError(`Invalid header name: "${name}"`);
// }
// if (!checkForInvalidValueChars(value)) {
// throw new TypeError(`Invalid header value: "${value}"`);
// }

// 3
if (headers.guard == "immutable") {
throw new TypeError("Cannot change header: headers are immutable");
}

// 7.
const list = headers.headerList;
const lowercaseName = byteLowerCase(name);
for (let i = 0; i < list.length; i++) {
if (byteLowerCase(list[i][0]) === lowercaseName) {
name = list[i][0];
break;
}
}
list.push([name, value]);
}

function normalizeHeaderValue(potentialValue) {
return httpTrim(potentialValue);
}

// TODO: move to web
function isHttpWhitespace(char) {
switch (char) {
case "\u0009":
case "\u000A":
case "\u000D":
case "\u0020":
return true;
default:
return false;
}
}

// const HTTP_BETWEEN_WHITESPACE = new SafeRegExp(
// `^[${HTTP_WHITESPACE_MATCHER}]*(.*?)[${HTTP_WHITESPACE_MATCHER}]*$`,
// );
// TODO: move to web
function httpTrim(s) {
if (!isHttpWhitespace(s[0]) && !isHttpWhitespace(s[s.length - 1])) {
return s;
}
// return String.prototype.match(s, HTTP_BETWEEN_WHITESPACE)?.[1] ?? "";
// TODO: implement to nova RegExp
return s;
}

// https://fetch.spec.whatwg.org/#concept-header-list-get
function getHeader(list, name) {
const lowercaseName = byteLowerCase(name);
const entries = [];
for (let i = 0; i < list.length; i++) {
if (byteLowerCase(list[i][0]) === lowercaseName) {
entries.push(list[i][1]);
}
}

if (entries.length === 0) {
return null;
} else {
return entries.join(entries, "\x2C\x20");
}
}
3 changes: 3 additions & 0 deletions runtime/src/ext/fetch/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod headers;

pub use headers::*;
2 changes: 2 additions & 0 deletions runtime/src/ext/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
mod console;
mod fetch;
mod fs;
mod process;
mod time;
mod url;
mod web;

pub use console::*;
pub use fetch::*;
pub use fs::*;
pub use process::*;
pub use time::*;
Expand Down
38 changes: 19 additions & 19 deletions runtime/src/ext/url/mod.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
// deno-lint-ignore-file no-unused-vars
class URL {
// TODO: Need to return a URL object.
constructor(url: string, base?: string) {
// @ts-ignore - this is a hack to make the URL object work
this.url = url;
// @ts-ignore - this is a hack to make the Base URL object work
this.base = base;
// @ts-ignore - this is a hack to make the URL object work
this.serialized = base
? internal_url_parse(url, base)
: internal_url_parse_no_base(url);
}
// TODO: Need to return a URL object.
constructor(url: string, base?: string) {
// @ts-ignore - this is a hack to make the URL object work
this.url = url;
// @ts-ignore - this is a hack to make the Base URL object work
this.base = base;
// @ts-ignore - this is a hack to make the URL object work
this.serialized = base
? internal_url_parse(url, base)
: internal_url_parse_no_base(url);
}

toString() {
// @ts-ignore - this is a hack to make the URL object work
return this.serialized;
}
toString() {
// @ts-ignore - this is a hack to make the URL object work
return this.serialized;
}

static parse(url: string, base?: string) {
return new this(url, base)
}
}
static parse(url: string, base?: string) {
return new this(url, base);
}
}
3 changes: 2 additions & 1 deletion runtime/src/recommended.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use andromeda_core::{Extension, HostData};
use nova_vm::ecmascript::execution::agent::{GcAgent, RealmRoot};

use crate::{ConsoleExt, FsExt, ProcessExt, RuntimeMacroTask, TimeExt, URLExt, WebExt};
use crate::{ConsoleExt, FsExt, HeadersExt, ProcessExt, RuntimeMacroTask, TimeExt, URLExt, WebExt};

pub fn recommended_extensions() -> Vec<Extension> {
vec![
Expand All @@ -11,6 +11,7 @@ pub fn recommended_extensions() -> Vec<Extension> {
ProcessExt::new_extension(),
URLExt::new_extension(),
WebExt::new_extension(),
HeadersExt::new_extension(),
]
}

Expand Down
3 changes: 1 addition & 2 deletions types/internals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ declare function internal_url_parse_no_base(url: string): string;
*/
declare function internal_btoa(input: string): string;
/**
*
* The `internal_atob` function decodes a string in base64.
*/
declare function internal_atob(input: string): string;
declare function internal_atob(input: string): string;
Loading