Skip to content

feat: URL & URLSearchParams #1801

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

Merged
merged 9 commits into from
Mar 28, 2024
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
4 changes: 3 additions & 1 deletion test-app/app/src/main/assets/app/mainpage.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,6 @@ require("./tests/testPackagePrivate");
require("./tests/kotlin/properties/testPropertiesSupport.js");
require('./tests/testNativeTimers');
require("./tests/testPostFrameCallback");
require("./tests/console/logTests.js");
require("./tests/console/logTests.js");
require('./tests/testURLImpl.js');
require('./tests/testURLSearchParamsImpl.js');
31 changes: 31 additions & 0 deletions test-app/app/src/main/assets/app/tests/testURLImpl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
describe("Test URL ", function () {

it("Test invalid URL parsing", function(){
var exceptionCaught = false;
try {
const url = new URL('');
}catch(e){
exceptionCaught = true;
}
expect(exceptionCaught).toBe(true);
});

it("Test valid URL parsing", function(){
var exceptionCaught = false;
try {
const url = new URL('https://google.com');
}catch(e){
exceptionCaught = true;
}
expect(exceptionCaught).toBe(false);
});


it("Test URL fields", function(){
var exceptionCaught = false;
const url = new URL('https://google.com');
expect(url.protocol).toBe('https:');
expect(url.hostname).toBe('google.com');
});

});
64 changes: 64 additions & 0 deletions test-app/app/src/main/assets/app/tests/testURLSearchParamsImpl.js

Choose a reason for hiding this comment

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

Nice to see tests 😍

Choose a reason for hiding this comment

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

Another good one to run Prettier formatting on.

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
describe("Test URLSearchParams ", function () {
const fooBar = "foo=1&bar=2";
it("Test URLSearchParams keys", function(){
const params = new URLSearchParams(fooBar);
const keys = params.keys();
expect(keys[0]).toBe("foo");
expect(keys[1]).toBe("bar");
});

it("Test URLSearchParams values", function(){
const params = new URLSearchParams(fooBar);
const values = params.values();
expect(values[0]).toBe("1");
expect(values[1]).toBe("2");
});


it("Test URLSearchParams entries", function(){
const params = new URLSearchParams(fooBar);
const entries = params.entries();
expect(entries[0][0]).toBe("foo");
expect(entries[0][1]).toBe("1");

expect(entries[1][0]).toBe("bar");
expect(entries[1][1]).toBe("2");

});


it("Test URLSearchParams size", function(){
const params = new URLSearchParams(fooBar);
expect(params.size).toBe(2);
});

it("Test URLSearchParams append", function(){
const params = new URLSearchParams(fooBar);
params.append("first", "Osei");
expect(params.get("first")).toBe("Osei");
});


it("Test URLSearchParams delete", function(){
const params = new URLSearchParams(fooBar);
params.append("first", "Osei");
params.delete("first");
expect(params.get("first")).toBe(undefined);
});


it("Test URLSearchParams has", function(){
const params = new URLSearchParams(fooBar);
expect(params.has("foo")).toBe(true);
});

it("Test URLSearchParams changes propagates to URL parent", function(){
const toBe = 'https://github.com/triniwiz?first=Osei';
const url = new URL('https://github.com/triniwiz');
const params = url.searchParams;
console.log(params);
params.set('first', 'Osei');
expect(url.toString()).toBe(toBe);
});

});
4 changes: 4 additions & 0 deletions test-app/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ include_directories(
src/main/cpp
src/main/cpp/include
src/main/cpp/v8_inspector
src/main/cpp/ada
)

if (OPTIMIZED_BUILD OR OPTIMIZED_WITH_INSPECTOR_BUILD)
Expand Down Expand Up @@ -137,6 +138,9 @@ add_library(
src/main/cpp/conversions/objects/JSToJavaObjectsConverter.cpp
src/main/cpp/conversions/arrays/JSToJavaArraysConverter.cpp
src/main/cpp/conversions/primitives/JSToJavaPrimitivesConverter.cpp
src/main/cpp/ada/ada.cpp
src/main/cpp/URLImpl.cpp
src/main/cpp/URLSearchParamsImpl.cpp

# V8 inspector source files will be included only in Release mode
${INSPECTOR_SOURCES}
Expand Down
73 changes: 73 additions & 0 deletions test-app/runtime/src/main/cpp/Runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <thread>
#include "File.h"
#include "ModuleBinding.h"
#include "URLImpl.h"
#include "URLSearchParamsImpl.h"

#ifdef APPLICATION_IN_DEBUG
// #include "NetworkDomainCallbackHandlers.h"
Expand Down Expand Up @@ -519,6 +521,9 @@ Isolate* Runtime::PrepareV8Runtime(const string& filesPath, const string& native
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__runOnMainThread"), FunctionTemplate::New(isolate, CallbackHandlers::RunOnMainThreadCallback));
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__postFrameCallback"), FunctionTemplate::New(isolate, CallbackHandlers::PostFrameCallback));
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__removeFrameCallback"), FunctionTemplate::New(isolate, CallbackHandlers::RemoveFrameCallback));
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "URL"), URLImpl::GetCtor(isolate));
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "URLSearchParams"), URLSearchParamsImpl::GetCtor(isolate));

/*
* Attach `Worker` object constructor only to the main thread (isolate)'s global object
* Workers should not be created from within other Workers, for now
Expand Down Expand Up @@ -586,10 +591,78 @@ Isolate* Runtime::PrepareV8Runtime(const string& filesPath, const string& native

Local<Context> context = Context::New(isolate, nullptr, globalTemplate);

auto blob_methods = R"js(
const BLOB_STORE = new Map();
URL.createObjectURL = function (object, options = null) {
try {
if (object instanceof Blob || object instanceof File) {
const id = java.util.UUID.randomUUID().toString();
const ret = `blob:nativescript/${id}`;
BLOB_STORE.set(ret, {
blob: object,
type: object?.type,
ext: options?.ext,
});
return ret;
}
} catch (error) {
return null;
}
return null;
};
URL.revokeObjectURL = function (url) {
BLOB_STORE.delete(url);
};
const InternalAccessor = class {};
InternalAccessor.getData = function (url) {
return BLOB_STORE.get(url);
};
URL.InternalAccessor = InternalAccessor;
Object.defineProperty(URL.prototype, 'searchParams', {
get() {
if (this._searchParams == null) {
this._searchParams = new URLSearchParams(this.search);
Object.defineProperty(this._searchParams, '_url', {
enumerable: false,
writable: false,
value: this,
});
this._searchParams._append = this._searchParams.append;
this._searchParams.append = function (name, value) {
this._append(name, value);
this._url.search = this.toString();
};
this._searchParams._delete = this._searchParams.delete;
this._searchParams.delete = function (name) {
this._delete(name);
this._url.search = this.toString();
};
this._searchParams._set = this._searchParams.set;
this._searchParams.set = function (name, value) {
this._set(name, value);
this._url.search = this.toString();
};
this._searchParams._sort = this._searchParams.sort;
this._searchParams.sort = function () {
this._sort();
this._url.search = this.toString();
};
}
return this._searchParams;
},
});
)js";


auto global = context->Global();

v8::Context::Scope contextScope{context};

v8::Local<v8::Script> script;
v8::Script::Compile(context, ArgConverter::ConvertToV8String(isolate, blob_methods)).ToLocal(&script);

v8::Local<v8::Value> out;
script->Run(context).ToLocal(&out);
m_objectManager->Init(isolate);

m_module.Init(isolate, callingDir);
Expand Down
Loading