Skip to content
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

feat: alpha8 module support #298

Merged
merged 4 commits into from
Apr 26, 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
2 changes: 0 additions & 2 deletions .github/workflows/build.ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ jobs:
- name: "Setup: GraalVM (Java ${{ vars.JVM_VERSION }})"
uses: graalvm/setup-graalvm@d1891786152ae96fee67f86c3a1eae596291bbed # v1
with:
components: "native-image,js"
version: '22.3.1'
java-version: ${{ vars.JVM_VERSION || '19' }}
check-for-updates: true
github-token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
4 changes: 2 additions & 2 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -345,9 +345,9 @@ http_archive(

## -- Dependency Setup -- ##

load("@google_bazel_common//:workspace_defs.bzl", "google_common_workspace_rules")
#load("@google_bazel_common//:workspace_defs.bzl", "google_common_workspace_rules")

google_common_workspace_rules()
#google_common_workspace_rules()

# toolchains

Expand Down
7 changes: 2 additions & 5 deletions elide/runtime/js/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ load(
"//elide/runtime/js:config.bzl",
"BASE_JS_EXTERNS",
"TS_MODULES",
"NODE_BUILTINS",
)

MODULE_NAME = "elide.runtime.js"
Expand Down Expand Up @@ -76,10 +77,6 @@ runtime_dist(
manifest = "MANIFEST.MF",
target = ":runtime",
modules = [
"//elide/runtime/js/modules/%s" % m for m in [
"buffer",
"express",
"fs",
]
"//elide/runtime/js/modules/%s" % m for m in NODE_BUILTINS
],
)
15 changes: 15 additions & 0 deletions elide/runtime/js/config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,18 @@ TS_MODULES = ["%s:%s" % (TS_MODULE_PACKAGE, t) for t in [
# General Modules
"//elide/runtime/js/bridge:js-error",
]

## Node Builtins
## -------------
## Registers each Node API built-in module.
NODE_BUILTINS = [
"assert",
"buffer",
"express",
"fs",
"inspector",
"os",
"path",
"process",
"util",
]
101 changes: 81 additions & 20 deletions elide/runtime/js/entrypoint.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ goog.require('elide.runtime.js.intrinsics.url.URL');
* Type structure of a Node process object.
*
* @typedef {{
* cwd: (function(): string),
* cwd: string,
* NODE_DEBUG: boolean,
* noDeprecation: boolean,
* browser: boolean,
Expand All @@ -28,22 +28,69 @@ goog.require('elide.runtime.js.intrinsics.url.URL');
let NodeProcess;

/**
* Global Node.js-style `process` object.
* Type structure of a Node process with extra Elide-provided properties.
*
* @type {!NodeProcess}
* @typedef {NodeProcess}
*/
let EnhancedNodeProcess;

/**
* Global symbol where application environment is injected.
*
* @const
* @type {!string}
*/
const process = {
'pid': -1,
'cwd': () => "",
'env': {},
'NODE_DEBUG': false,
'NODE_ENV': "production",
'noDeprecation': false,
'browser': false,
'version': 'v18.9.0'
};
const APP_ENV = '__Elide_app_env__';

/**
* Global symbol where Elide version is injected.
*
* @const
* @type {!string}
*/
const RUNTIME_VERSION = '__Elide_version__';

/**
* Global symbol where the intrinsic process object is injected.
*
* @const
* @type {!string}
*/
const RUNTIME_PROCESS = '__Elide_node_process__';

/**
* Application environment injected by the Elide runtime.
*
* @type {!Object<string, !string>}
*/
const injectedApplicationEnvironment = globalThis[APP_ENV];

/**
* Elide version provided by the runtime.
*
* @type {!string}
*/
const elideVersion = globalThis[RUNTIME_VERSION];

/**
* Intrinsic process object, injected by the runtime.
*
* @type {!EnhancedNodeProcess}
*/
const intrinsicProcess = globalThis[RUNTIME_PROCESS];

/**
* Return the Node Process API to use.
*
* @returns {!EnhancedNodeProcess}
*/
function nodeProcessAPI() {
if (!intrinsicProcess) {
throw new Error('Node process API is not available.');
}
return intrinsicProcess;
}

globalThis['process'] = process;
globalThis['window'] = undefined;
globalThis['gc'] = null;

Expand All @@ -60,18 +107,32 @@ globalThis['self'] = App;
* Global Elide object.
*
* @type {{
* process: !NodeProcess,
* context: {build: boolean, runtime: boolean},
* self: *
* version: !string,
* process: !EnhancedNodeProcess,
* context: {build: boolean, runtime: boolean}
* }}
*/
const Elide = {
'process': process,
'self': globalThis,
'process': nodeProcessAPI(),
'version': elideVersion,
'context': {
'build': false,
'runtime': true
},
'App': App,
};

globalThis['Elide'] = Elide;

/**
* Global process proxy object.
*
* @type {!EnhancedNodeProcess}
*/
const process = /** @type {!EnhancedNodeProcess} */ ({
'pid': Elide.process.pid,
'cwd': Elide.process.cwd,
'env': Elide.process.env,
...(Elide.process || {}),
});

globalThis['process'] = process;
12 changes: 12 additions & 0 deletions elide/runtime/js/modules/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
load(
"//tools/defs/esbuild:exports.bzl",
"esbuild_config",
)
package(
default_visibility = ["//visibility:public"],
)

esbuild_config(
name = "esbuild-config",
config_file = "esbuild.config.js",
)
15 changes: 15 additions & 0 deletions elide/runtime/js/modules/assert/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package(
default_visibility = ["//visibility:public"],
)
load(
"//tools/defs:elide.bzl",
"js_module",
)

js_module(
name = "assert",
srcs = [
"assert.ts",
"index.ts",
],
)
179 changes: 179 additions & 0 deletions elide/runtime/js/modules/assert/assert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/**
* Intrinsic: Assertions.
*
* Provides assertion primitives for use in testing and debugging.
*/

/**
* Type: `AssertionErrorOptions`.
*
* Shape of options that can be provided to a new `AssertionError`.
*/
export interface AssertionErrorOptions {
/** If provided, the error message is set to this value. */
message?: string;

/** The `actual` property on the error instance. */
actual?: any;

/** The `expected` property on the error instance. */
expected?: any;

/** The `operator` property on the error instance. */
operator?: string;

/* If provided, the generated stack trace omits frames before this function. */
stackStartFn?: Function;
}

/**
* Type: `AssertionError`
*
* Represents an assertion failure.
*/
export class AssertionError implements Error, AssertionErrorOptions {
public name: string;
public message: string;
public actual: any;
public expected: any;
public operator?: string;
public generatedMessage: boolean;
public code: string;
public stack: string;

/**
* Primary constructor.

* @param options Options for the assertion error.
*/
constructor(options: AssertionErrorOptions) {
this.name = "AssertionError";
this.message = options.message || "";
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
this.generatedMessage = !options.message;
this.code = "ERR_ASSERTION";
this.stack = new Error().stack || "";
}

toString() {
return this.stack;
}
}

/**
* Checks if a condition is truthy, throwing an `AssertionError` if it is not.
*
* @param condition Condition to check for truthiness.
* @param message Message to provide if the condition is falsy.
* @throws `AssertionError` if the condition is falsy.
* @see https://nodejs.org/api/assert.html#assertokvalue-message
*/
export function ok(condition: any, message?: string): void {
if (!condition) {
throw new AssertionError({ message });
}
}

/**
* Alias for function `ok`.
*
* @see https://nodejs.org/api/assert.html#assertvalue-message
*/
export const assert = ok;

/**
* Checks if two values are equal, throwing an `AssertionError` if they are not.
*
* @param actual Actual value to test for equality.
* @param expected Expected value to test for equality.
* @param message Message to display, or error to throw, if the equality check fails.
* @throws `AssertionError` if the actual value is not equal to the expected value.
* @see https://nodejs.org/api/assert.html#assertequalactual-expected-message
*/
export function equal(actual: any, expected: any, message?: string | Error): void {
if (actual != expected) {
if (message) {
if (message instanceof Error) {
throw message;
} else {
throw new AssertionError({
operator: '==',
message: message || `Expected ${actual} to equal ${expected}`,
stackStartFn: equal,
actual,
expected,
});
}
}
}
}

/**
* Checks if two object values are deeply equal, throwing an `AssertionError` if they are equal.
*
* Tests for deep equality between the `actual` and `expected` values. Recursively checks the equality of all owned
* properties.
*
* Deep equality means that the enumerable "own" properties of child objects are also recursively evaluated by the
* following rules:
*
* - Primitive values are compared with the `==` operator, with the exception of `NaN`. It is treated as being
* identical if both sides are `NaN`.
* - Type tags of objects should be the same.
* - Only enumerable "own" properties are considered.
* - `Error` names and messages are always compared, even if these are not enumerable properties.
* - Object wrappers are compared both as objects and unwrapped values.
* - `Object` properties are compared unordered.
* - Recursion stops when both sides differ or both sides encounter a circular reference.
* - Implementation does not test the `[[Prototype]]` of objects.
* - `Symbol` properties are not compared.
* - `WeakMap` and `WeakSet` comparison does not rely on their values.
* - `RegExp` lastIndex, flags, and source are always compared, even if these are not enumerable properties.
*
* This method is considered legacy within the Node API, and it is recommended that developers use `deepStrictEqual`
* for most purposes instead.
*
* @param actual Actual object value to test for deep equality.
* @param expected Expected object value to test for deep equality.
* @param message Message to display, or error to throw, if the equality check fails.
* @see https://nodejs.org/api/assert.html#assertdeepequalactual-expected-message
*/
export function deepEqual(actual: any, expected: any, message?: string | Error): void {
throw new Error("Not implemented: `assert.deepEqual`")
}

/**
* Checks if two object values are deeply and strictly equal, throwing an `AssertionError` if they are equal.
*
* Tests for deep and strict equality between the `actual` and `expected` values. Recursively checks the
* strict equality of all owned properties.
*
* Deep equality means that the enumerable "own" properties of child objects are also recursively evaluated by the
* following rules:
*
* - Primitive values are compared using `Object.is`
* - Type tags of objects should be the same.
* - `[[Prototype]]` of objects is compared using the `===` operator.
* - Only enumerable "own" properties are considered.
* - `Error` names and messages are always compared, even if these are not enumerable properties.
* - Enumerable own `Symbol` properties are compared as well.
* - Object wrappers are compared both as objects and unwrapped values.
* - `Object` properties are compared unordered.
* - `Map` keys and `Set` items are compared unordered.
* - Recursion stops when both sides differ or both sides encounter a circular reference.
* - `WeakMap` and `WeakSet` comparison does not rely on their values.
* - `RegExp` lastIndex, flags, and source are always compared, even if these are not enumerable properties.
*
* @param actual Actual object value to test for deep equality.
* @param expected Expected object value to test for deep equality.
* @param message Message to display, or error to throw, if the equality check fails.
* @see https://nodejs.org/api/assert.html#assertdeepequalactual-expected-message
*/
export function deepStrictEqual(actual: any, expected: any, message?: string | Error): void {
throw new Error("Not implemented: `assert.deepStrictEqual`")
}

// Export the `assert` function as the default entrypoint for the module.
export default assert;
Loading
Loading