Skip to content

Commit

Permalink
Add architecture detection
Browse files Browse the repository at this point in the history
  • Loading branch information
Hexagon committed Mar 6, 2024
1 parent 20c1719 commit 3cefc73
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
node_modules
.npmrc
test.js
package.json
package-lock.json

# Deno
Expand Down
29 changes: 24 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,25 @@

**Cross-Runtime Environment Detection for JavaScript and TypeScript**

This package provides a robust, cross runtime, way to determine the current runtime environment (Deno, Bun, Node.js, or browser) along with detailed browser detection.
This package provides a well defined, cross runtime, way to determine details about the current runtime environment (Deno, Bun, Node.js, or browser) along with detailed browser detection.

Try it out at [jsfiddle.net/ux87tLz4/6/](https://jsfiddle.net/ux87tLz4/6/)

**Usage Example**

```javascript
import { CurrentProduct, CurrentRuntime, CurrentVersion, Runtime } from "@cross/runtime";
import {
CurrentOS,
CurrentProduct,
CurrentArchitecture,
CurrentRuntime,
CurrentVersion,
Runtime
} from "@cross/runtime";

console.log(`Runtime: ${CurrentRuntime}`);
console.log(`OS: ${CurrentOS}`);
console.log(`Architecture: ${CurrentArchitecture}`);
console.log(`Product: ${CurrentProduct}`);
console.log(`Version: ${CurrentVersion}`);
console.log(`Version: ${CurrentVersion}\n`);

if (CurrentRuntime == Runtime.Deno) {
console.log("You're running Deno!");
Expand All @@ -22,6 +29,18 @@ if (CurrentRuntime == Runtime.Deno) {
}
```

This script results in something like:

```
Runtime: bun
OS: linux
Architecture: x86_64
Product: bun
Version: 1.0.30
You're not running Deno!
```

**Full Documentation**

For comprehensive documentation, including more advanced usage and examples, please visit the official JSR documentation (if your are not already there):
Expand Down
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cross/runtime",
"version": "0.0.14",
"version": "0.0.15",
"exports": "./mod.ts",
"fmt": {
"lineWidth": 200
Expand Down
6 changes: 5 additions & 1 deletion mod.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CurrentOS, OperatingSystem } from "./mod.ts";
import { CurrentProduct, CurrentRuntime, CurrentVersion, Product, Runtime } from "./mod.ts";
import { assertEquals } from "jsr:@std/assert";
import { assertEquals, assertNotEquals } from "jsr:@std/assert";

Deno.test("Current runtime is Deno (string)", () => {
assertEquals("deno", CurrentRuntime);
Expand All @@ -16,3 +17,6 @@ Deno.test("Current product is Deno (enum)", () => {
Deno.test("Current version contains a dot", () => {
assertEquals(true, CurrentVersion?.includes("."));
});
Deno.test("Current operating system is supported", () => {
assertNotEquals(OperatingSystem.Unsupported, CurrentOS);
});
187 changes: 176 additions & 11 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,6 @@ function getBraveVersion() {
return match ? match[2] : "Unknown";
}

function getVivaldiVersion() {
const ua = navigator.userAgent;
const match = ua.match(/Vivaldi\/([0-9]+)\./);
return match ? match[1] : "Unknown";
}

/**
* Enum of supported Runtimes.
* @enum {string}
Expand All @@ -58,6 +52,20 @@ export enum Runtime {
Unsupported = "unsupported",
}

/**
* Enum of supported Operating Systems.
* @enum {string}
*/
export enum OperatingSystem {
Windows = "windows",
macOS = "macos",
Linux = "linux",
Android = "android",
Unix = "unix",
iOS = "ios",
Unsupported = "unsupported",
}

/**
* Enum of supported Products.
* @enum {string}
Expand All @@ -75,12 +83,23 @@ export enum Product {
Edge = "edge",
Opera = "opera",
Brave = "brave",
Vivaldi = "vivaldi",

// And unsupported
Unsupported = "unsupported",
}

/**
* Enum of common CPU architectures.
* @enum {string}
*/
export enum Architecture {
x86 = "x86",
x64 = "x86_64",
arm = "arm",
arm64 = "arm64",
Unsupported = "unsupported",
}

/**
* Dynamically determines the current runtime environment.
*/
Expand All @@ -107,6 +126,80 @@ export function getCurrentRuntime(): Runtime {
}
}

/**
* Dynamically determines the current operating system.
*/
export function getCurrentOS(): OperatingSystem {
const runtime = getCurrentRuntime();
switch (runtime) {
case Runtime.Deno:
switch (Deno.build.os) {
case "darwin":
return OperatingSystem.macOS;
case "windows":
return OperatingSystem.Windows;
case "linux":
return OperatingSystem.Linux;
case "android":
return OperatingSystem.Android;
case "aix":
case "freebsd":
case "illumos":
case "netbsd":
case "solaris":
return OperatingSystem.Unix;
}
return OperatingSystem.Unsupported;
case Runtime.Node:
// @ts-ignore Cross Runtime
switch (process.platform) {
case "darwin":
return OperatingSystem.macOS;
case "win32":
return OperatingSystem.Windows;
case "linux":
return OperatingSystem.Linux;
case "android":
return OperatingSystem.Android;
case "aix":
case "freebsd":
case "openbsd":
case "sunos":
return OperatingSystem.Unix;
}
return OperatingSystem.Unsupported;
case Runtime.Bun:
// @ts-ignore Cross Runtime
switch (process.platform) {
case "darwin":
return OperatingSystem.macOS;
case "win32":
return OperatingSystem.Windows;
case "linux":
return OperatingSystem.Linux;
case "android":
return OperatingSystem.Android;
case "aix":
case "freebsd":
case "openbsd":
case "sunos":
return OperatingSystem.Unix;
}
return OperatingSystem.Unsupported;
case Runtime.Browser: {
if ("userAgent" in navigator) {
const userAgent = navigator.userAgent;
if (userAgent.indexOf("Win") !== -1) return OperatingSystem.Windows;
if (userAgent.indexOf("like Mac") !== -1) return OperatingSystem.iOS;
if (userAgent.indexOf("Mac") !== -1) return OperatingSystem.macOS;
if (userAgent.indexOf("Android") !== -1) return OperatingSystem.Android;
if (userAgent.indexOf("X11") !== -1 || userAgent.indexOf("Linux") !== -1) return OperatingSystem.Linux;
}
}
}
return OperatingSystem.Unsupported;
}

/**
* Dynamically determines the current browser and its version (if applicable).
*/
Expand All @@ -126,8 +219,6 @@ export function getCurrentProduct(): Product {
return Product.Opera;
} else if ("brave" in navigator) {
return Product.Brave;
} else if (userAgent.indexOf("Vivaldi") !== -1) {
return Product.Vivaldi;
} else if (userAgent.indexOf("Safari") !== -1 && userAgent.indexOf("Chrome") === -1) {
return Product.Safari;
} else if (userAgent.indexOf("Edg") !== -1) {
Expand Down Expand Up @@ -173,13 +264,77 @@ export function getCurrentVersion(): string | undefined {
return getOperaVersion();
case Product.Brave:
return getBraveVersion();
case Product.Vivaldi:
return getVivaldiVersion();
default:
return undefined;
}
}

/**
* Attempts to determine the current CPU architecture of the runtime's environment.
*/
export function getCurrentArchitecture(): Architecture {
const runtime = getCurrentRuntime();
switch (runtime) {
case Runtime.Deno:
if (Deno.build.arch === "x86_64") {
return Architecture.x64;
}
if (Deno.build.arch === "aarch64") {
return Architecture.arm64;
}
if (Deno.build.os === "darwin") {
return Architecture.x64;
}
return Architecture.x86;
case Runtime.Bun:
case Runtime.Node:
// @ts-ignore Cross Runtime
switch (process.arch) {
case "arm":
return Architecture.arm;
case "arm64":
return Architecture.arm64;
case "ia32":
return Architecture.x86;
case "x64":
return Architecture.x64;
case "loong64":
case "mips":
case "mipsel":
case "ppc":
case "ppc64":
case "riscv64":
case "s390":
case "s390x":
return Architecture.Unsupported;
}
return Architecture.Unsupported;
case Runtime.Browser: {
const userAgent = navigator.userAgent;
// @ts-ignore Cross Runtime
const platform = navigator.platform;
// Clues for x86/x64
if (platform.indexOf("Win64") !== -1 || platform.indexOf("x64") !== -1) {
return Architecture.x64;
} else if (platform.indexOf("Win32") !== -1 || platform.indexOf("x86") !== -1) {
return Architecture.x86;
}
// Clues for ARM
if (userAgent.indexOf("arm64") !== -1) {
return Architecture.arm64;
} else if (userAgent.indexOf("arm") !== -1) {
return Architecture.arm;
// @ts-ignore Cross Runtime
} else if (platform.indexOf("iPhone") || platform.indexOf("iPad") || (userAgent.indexOf("Mac") !== -1 && "ontouchend" in document)) {
// Likely aarch64 on newer iOS devices and Apple Silicon Macs
return Architecture.arm64;
}
return Architecture.Unsupported;
}
}
return Architecture.Unsupported;
}

/**
* Static variable containing the current runtime.
*/
Expand All @@ -194,3 +349,13 @@ export const CurrentProduct: Product = getCurrentProduct();
* Static variable containing the current product/runtime version.
*/
export const CurrentVersion: string | undefined = getCurrentVersion();

/**
* Static variable containing the current operating system.
*/
export const CurrentOS: string | undefined = getCurrentOS();

/**
* Static variable containing the current operating system.
*/
export const CurrentArchitecture: string | undefined = getCurrentArchitecture();

0 comments on commit 3cefc73

Please sign in to comment.