Compare commits

...

8 Commits

Author SHA1 Message Date
Meghan Denny
1bdbcb2839 Merge branch 'main' into nektro-patch-39805 2025-01-17 22:26:30 -08:00
Meghan Denny
37ee78f980 Merge branch 'main' into nektro-patch-39805 2024-10-03 00:22:25 -07:00
Meghan Denny
afbd411841 dont commit this 2024-10-02 00:37:07 -07:00
Meghan Denny
727914024f add Navigator to docs globals.md 2024-09-30 15:51:24 -07:00
Meghan Denny
ede6f23ee2 update types 2024-09-28 05:12:12 -07:00
Meghan Denny
1c02febb54 update test 2024-09-28 05:12:06 -07:00
Meghan Denny
a51da8dbca fix linux zig build 2024-09-28 04:18:18 -07:00
Meghan Denny
5828599583 js: add Navigator global and make navigator and instance of it 2024-09-28 04:07:39 -07:00
13 changed files with 143 additions and 43 deletions

View File

@@ -212,6 +212,12 @@ Bun implements the following globals.
---
- [`Navigator`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator)
- Node.js
- See [Node.js > `Navigator`](https://nodejs.org/docs/latest/api/globals.html#navigator).
---
- [`performance`](https://developer.mozilla.org/en-US/docs/Web/API/performance)
- Web
-  

View File

@@ -317,6 +317,14 @@ The table below lists all globals implemented by Node.js and Bun's current compa
🟢 Fully implemented.
### [`Navigator`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator)
🟢 Fully implemented.
### [`navigator`](https://nodejs.org/api/globals.html#navigator_1)
🟢 Fully implemented.
### [`PerformanceEntry`](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry)
🟢 Fully implemented.

View File

@@ -86,6 +86,7 @@ The following Web APIs are partially or completely supported.
- Debugging
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)
[`navigator`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator)
[`performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance)
---

View File

@@ -1899,8 +1899,10 @@ declare global {
interface Navigator {
readonly userAgent: string;
readonly platform: "MacIntel" | "Win32" | "Linux x86_64";
readonly platform: string;
readonly hardwareConcurrency: number;
readonly language: string;
readonly languages: string[];
}
var navigator: Navigator;

View File

@@ -2976,40 +2976,7 @@ void GlobalObject::finishCreation(VM& vm)
m_navigatorObject.initLater(
[](const Initializer<JSObject>& init) {
int cpuCount = 0;
#ifdef __APPLE__
size_t count_len = sizeof(cpuCount);
sysctlbyname("hw.logicalcpu", &cpuCount, &count_len, NULL, 0);
#elif OS(WINDOWS)
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
cpuCount = sysinfo.dwNumberOfProcessors;
#else
// TODO: windows
cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
#endif
auto str = WTF::String::fromUTF8(Bun__userAgent);
JSC::Identifier userAgentIdentifier = JSC::Identifier::fromString(init.vm, "userAgent"_s);
JSC::Identifier hardwareConcurrencyIdentifier = JSC::Identifier::fromString(init.vm, "hardwareConcurrency"_s);
JSC::JSObject* obj = JSC::constructEmptyObject(init.owner, init.owner->objectPrototype(), 4);
obj->putDirect(init.vm, userAgentIdentifier, JSC::jsString(init.vm, str));
obj->putDirect(init.vm, init.vm.propertyNames->toStringTagSymbol,
jsNontrivialString(init.vm, "Navigator"_s), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
// https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform
// https://github.com/oven-sh/bun/issues/4588
#if OS(DARWIN)
obj->putDirect(init.vm, JSC::Identifier::fromString(init.vm, "platform"_s), JSC::jsString(init.vm, String("MacIntel"_s)));
#elif OS(WINDOWS)
obj->putDirect(init.vm, JSC::Identifier::fromString(init.vm, "platform"_s), JSC::jsString(init.vm, String("Win32"_s)));
#elif OS(LINUX)
obj->putDirect(init.vm, JSC::Identifier::fromString(init.vm, "platform"_s), JSC::jsString(init.vm, String("Linux x86_64"_s)));
#endif
obj->putDirect(init.vm, hardwareConcurrencyIdentifier, JSC::jsNumber(cpuCount));
init.set(obj);
init.set(JSC::constructEmptyObject(init.vm, jsCast<Zig::GlobalObject*>(init.owner)->NavigatorStructure()));
});
this->m_pendingVirtualModuleResultStructure.initLater(

View File

@@ -184,6 +184,10 @@ public:
JSC::Structure* FFIFunctionStructure() const { return m_JSFFIFunctionStructure.getInitializedOnMainThread(this); }
JSC::Structure* NapiClassStructure() const { return m_NapiClassStructure.getInitializedOnMainThread(this); }
JSC::Structure* NavigatorStructure() const { return m_JSNavigator.getInitializedOnMainThread(this); }
JSC::JSObject* Navigator() const { return m_JSNavigator.constructorInitializedOnMainThread(this); }
JSC::JSValue NavigatorPrototype() const { return m_JSNavigator.prototypeInitializedOnMainThread(this); }
JSC::Structure* FileSinkStructure() const { return m_JSFileSinkClassStructure.getInitializedOnMainThread(this); }
JSC::JSObject* FileSink() const { return m_JSFileSinkClassStructure.constructorInitializedOnMainThread(this); }
JSC::JSValue FileSinkPrototype() const { return m_JSFileSinkClassStructure.prototypeInitializedOnMainThread(this); }

View File

@@ -21,7 +21,7 @@
setInterval functionSetInterval Function 1
setTimeout functionSetTimeout Function 1
structuredClone functionStructuredClone Function 2
global GlobalObject_getGlobalThis PropertyCallback
Bun GlobalObject::m_bunObject CellProperty|DontDelete|ReadOnly
@@ -37,6 +37,7 @@
BuildMessage GlobalObject::m_JSBuildMessage ClassStructure
Crypto GlobalObject::m_JSCrypto ClassStructure
HTMLRewriter GlobalObject::m_JSHTMLRewriter ClassStructure
Navigator GlobalObject::m_JSNavigator ClassStructure
Request GlobalObject::m_JSRequest ClassStructure
ResolveError GlobalObject::m_JSResolveMessage ClassStructure
ResolveMessage GlobalObject::m_JSResolveMessage ClassStructure

View File

@@ -78,8 +78,8 @@ pub const Classes = struct {
pub const NativeBrotli = JSC.API.NativeBrotli;
pub const FrameworkFileSystemRouter = bun.bake.FrameworkRouter.JSFrameworkRouter;
pub const DNSResolver = JSC.DNS.DNSResolver;
pub const S3Client = JSC.WebCore.S3Client;
pub const S3Stat = JSC.WebCore.S3Stat;
pub const HTMLBundle = JSC.API.HTMLBundle;
pub const Navigator = JSC.API.Navigator;
};

View File

@@ -0,0 +1,92 @@
const std = @import("std");
const bun = @import("root").bun;
const Environment = bun.Environment;
const JSC = bun.JSC;
const string = bun.string;
const Output = bun.Output;
const ZigString = JSC.ZigString;
pub const Navigator = struct {
pub usingnamespace bun.NewRefCounted(@This(), deinit);
pub usingnamespace JSC.Codegen.JSNativeZlib;
ref_count: u32 = 1,
pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) ?*@This() {
_ = callframe;
globalThis.ERR_ILLEGAL_CONSTRUCTOR("Illegal constructor", .{}).throw();
return null;
}
pub fn get_hardwareConcurrency(_: *@This(), globalThis: *JSC.JSGlobalObject) JSC.JSValue {
_ = globalThis;
switch (bun.Environment.os) {
.mac => {
var cpu_count: c_int = 0;
var cpu_len: usize = @sizeOf(c_int);
_ = std.c.sysctlbyname("hw.logicalcpu", &cpu_count, &cpu_len, null, 0);
return JSC.jsNumber(cpu_count);
},
.linux => {
const c = struct {
extern "c" fn sysconf(sc: c_int) i64;
const _SC_NPROCESSORS_ONLN = 84;
};
const cpu_count = c.sysconf(c._SC_NPROCESSORS_ONLN);
return JSC.jsNumber(cpu_count);
},
.windows => {
var sysinfo = std.mem.zeroes(std.os.windows.SYSTEM_INFO);
bun.windows.kernel32.GetSystemInfo(&sysinfo);
return JSC.jsNumber(sysinfo.dwNumberOfProcessors);
},
.wasm => {
return JSC.jsNumber(1);
},
}
}
pub fn get_language(_: *@This(), globalThis: *JSC.JSGlobalObject) JSC.JSValue {
// TODO: query ICU for default locale
return bun.String.static("en-US").toJS(globalThis);
}
pub fn get_languages(this: *@This(), globalThis: *JSC.JSGlobalObject) JSC.JSValue {
return JSC.JSArray.create(globalThis, &.{
this.get_language(globalThis),
});
}
pub fn get_platform(_: *@This(), globalThis: *JSC.JSGlobalObject) JSC.JSValue {
switch (bun.Environment.os) {
.mac => {
// On macOS, modern browsers return 'MacIntel' even if running on Apple Silicon.
return bun.String.static("MacIntel").toJS(globalThis);
},
.windows => {
// On Windows, modern browsers return 'Win32' even if running on a 64-bit version of Windows.
return bun.String.static("Win32").toJS(globalThis);
},
.linux => switch (bun.Environment.arch) {
.x64 => return bun.String.static("Linux x86_64").toJS(globalThis),
else => {},
},
.wasm => {},
}
return bun.String.static(bun.Environment.os.displayString() ++ " " ++ @tagName(bun.Environment.arch)).toJS(globalThis);
}
pub fn get_userAgent(_: *@This(), globalThis: *JSC.JSGlobalObject) JSC.JSValue {
return bun.String.static(bun.Global.user_agent).toJS(globalThis);
}
pub fn set_noop(_: *@This(), globalThis: *JSC.JSGlobalObject, newValue: JSC.JSValue) bool {
_ = globalThis;
_ = newValue;
return true;
}
pub fn deinit(this: *@This()) void {
this.destroy();
}
};

View File

@@ -0,0 +1,17 @@
import { define } from "../../codegen/class-definitions";
export default [
define({
name: "Navigator",
construct: true,
klass: {},
JSType: "0b11101110",
proto: {
hardwareConcurrency: { getter: "get_hardwareConcurrency", setter: "set_noop" },
language: { getter: "get_language", setter: "set_noop" },
languages: { getter: "get_languages", setter: "set_noop" },
platform: { getter: "get_platform", setter: "set_noop" },
userAgent: { getter: "get_userAgent", setter: "set_noop" },
},
}),
];

View File

@@ -84,7 +84,7 @@ pub const OperatingSystem = enum {
});
/// user-facing name with capitalization
pub fn displayString(self: OperatingSystem) []const u8 {
pub inline fn displayString(self: OperatingSystem) []const u8 {
return switch (self) {
.mac => "macOS",
.linux => "Linux",
@@ -94,7 +94,7 @@ pub const OperatingSystem = enum {
}
/// same format as `process.platform`
pub fn nameString(self: OperatingSystem) []const u8 {
pub inline fn nameString(self: OperatingSystem) []const u8 {
return switch (self) {
.mac => "darwin",
.linux => "linux",
@@ -103,7 +103,7 @@ pub const OperatingSystem = enum {
};
}
pub fn stdOSTag(self: OperatingSystem) std.Target.Os.Tag {
pub inline fn stdOSTag(self: OperatingSystem) std.Target.Os.Tag {
return switch (self) {
.mac => .macos,
.linux => .linux,
@@ -113,7 +113,7 @@ pub const OperatingSystem = enum {
}
/// npm package name, `@oven-sh/bun-{os}-{arch}`
pub fn npmName(self: OperatingSystem) []const u8 {
pub inline fn npmName(self: OperatingSystem) []const u8 {
return switch (self) {
.mac => "darwin",
.linux => "linux",
@@ -140,7 +140,7 @@ pub const Architecture = enum {
wasm,
/// npm package name, `@oven-sh/bun-{os}-{arch}`
pub fn npmName(this: Architecture) []const u8 {
pub inline fn npmName(this: Architecture) []const u8 {
return switch (this) {
.x64 => "x64",
.arm64 => "aarch64",

View File

@@ -54,6 +54,7 @@ pub const API = struct {
pub const NativeZlib = @import("./bun.js/node/node_zlib_binding.zig").SNativeZlib;
pub const NativeBrotli = @import("./bun.js/node/node_zlib_binding.zig").SNativeBrotli;
pub const HTMLBundle = @import("./bun.js/api/server/HTMLBundle.zig");
pub const Navigator = @import("./bun.js/node/navigator.zig").Navigator;
};
pub const Postgres = @import("./sql/postgres.zig");
pub const DNS = @import("./bun.js/api/bun/dns_resolver.zig");

View File

@@ -30,6 +30,7 @@ test("exists", () => {
expect(typeof PerformanceResourceTiming !== "undefined").toBe(true);
expect(typeof PerformanceServerTiming !== "undefined").toBe(true);
expect(typeof PerformanceTiming !== "undefined").toBe(true);
expect(typeof Navigator !== "undefined").toBe(true);
});
const globalSetters = [
@@ -239,7 +240,7 @@ test("navigator", () => {
} else if (isWindows) {
expect(navigator.platform).toBe("Win32");
} else if (isLinux) {
expect(navigator.platform).toBe("Linux x86_64");
expect(navigator.platform).toBe(`Linux ${process.arch === "x64" ? "x86_64" : process.arch}`);
}
});