aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2023-04-04 16:49:33 -0700
committerGravatar GitHub <noreply@github.com> 2023-04-04 16:49:33 -0700
commita369fc8c8969b0f2d823bed5a7565d245311345b (patch)
tree1b8c16d0d5506d9fd6c3510e472588684e718030
parent54d6f95f43774f92dddcbd91a669eec4a9f24d38 (diff)
downloadbun-a369fc8c8969b0f2d823bed5a7565d245311345b.tar.gz
bun-a369fc8c8969b0f2d823bed5a7565d245311345b.tar.zst
bun-a369fc8c8969b0f2d823bed5a7565d245311345b.zip
Implement `import.meta.main` (#2556)
* Implement `import.meta.main` * Update main-test-1.js * Update fs.test.ts --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
-rw-r--r--packages/bun-types/globals.d.ts27
-rw-r--r--src/bun.js/bindings/ImportMetaObject.cpp11
-rw-r--r--src/bun.js/builtins/cpp/ImportMetaObjectBuiltins.cpp11
-rw-r--r--src/bun.js/builtins/cpp/ImportMetaObjectBuiltins.h9
-rw-r--r--src/bun.js/builtins/cpp/ProcessObjectInternalsBuiltins.cpp5
-rw-r--r--src/bun.js/builtins/js/ImportMetaObject.js7
-rw-r--r--test/js/bun/resolve/import-meta.test.js14
-rw-r--r--test/js/bun/resolve/main-test-1.js5
-rw-r--r--test/js/bun/resolve/main-test-script.js7
-rw-r--r--test/js/node/fs/fs.test.ts1
10 files changed, 89 insertions, 8 deletions
diff --git a/packages/bun-types/globals.d.ts b/packages/bun-types/globals.d.ts
index 6ff2e9970..a9fdc01a1 100644
--- a/packages/bun-types/globals.d.ts
+++ b/packages/bun-types/globals.d.ts
@@ -234,21 +234,21 @@ interface ImportMeta {
* "file:///Users/me/projects/my-app/src/my-app.ts"
* ```
*/
- url: string;
+ readonly url: string;
/**
* Absolute path to the source file
*/
- path: string;
+ readonly path: string;
/**
* Absolute path to the directory containing the source file.
*
* Does not have a trailing slash
*/
- dir: string;
+ readonly dir: string;
/**
* Filename of the source file
*/
- file: string;
+ readonly file: string;
/**
* Resolve a module ID the same as if you imported it
*
@@ -284,6 +284,25 @@ interface ImportMeta {
* relevant.
*/
require: NodeJS.Require;
+
+ /**
+ * Did the current file start the process?
+ *
+ * @example
+ * ```ts
+ * if (import.meta.main) {
+ * console.log("I started the process!");
+ * }
+ * ```
+ *
+ * @example
+ * ```ts
+ * console.log(
+ * import.meta.main === (import.meta.path === Bun.main)
+ * )
+ * ```
+ */
+ readonly main: boolean;
}
/**
diff --git a/src/bun.js/bindings/ImportMetaObject.cpp b/src/bun.js/bindings/ImportMetaObject.cpp
index f8b6d0f9b..7831cf881 100644
--- a/src/bun.js/bindings/ImportMetaObject.cpp
+++ b/src/bun.js/bindings/ImportMetaObject.cpp
@@ -39,6 +39,7 @@
#include "JSDOMURL.h"
#include "JavaScriptCore/JSNativeStdFunction.h"
+#include "JavaScriptCore/GetterSetter.h"
namespace Zig {
using namespace JSC;
@@ -84,7 +85,7 @@ static EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObject,
// require.resolve also supports a paths array
// we only support a single path
if (!fromValue.isUndefinedOrNull() && fromValue.isObject()) {
- if (JSValue pathsValue = fromValue.getObject()->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "paths"_s))) {
+ if (JSValue pathsValue = fromValue.getObject()->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "paths"_s))) {
if (JSC::JSArray* array = JSC::jsDynamicCast<JSC::JSArray*>(pathsValue)) {
if (array->length() > 0) {
fromValue = array->getIndex(globalObject, 0);
@@ -413,7 +414,13 @@ void ImportMetaObjectPrototype::finishCreation(VM& vm, JSGlobalObject* globalObj
this->putDirect(vm, builtinNames.dirPublicName(), jsEmptyString(vm), 0);
this->putDirect(vm, builtinNames.pathPublicName(), jsEmptyString(vm), 0);
this->putDirect(vm, builtinNames.urlPublicName(), jsEmptyString(vm), 0);
- this->putDirect(vm, builtinNames.mainPublicName(), jsBoolean(false), 0);
+
+ this->putDirect(
+ vm,
+ builtinNames.mainPublicName(),
+ GetterSetter::create(vm, globalObject, JSFunction::create(vm, importMetaObjectMainCodeGenerator(vm), globalObject), nullptr),
+ JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin | 0);
+
this->putDirect(vm, Identifier::fromString(vm, "primordials"_s), jsUndefined(), JSC::PropertyAttribute::DontEnum | 0);
String requireString = "[[require]]"_s;
diff --git a/src/bun.js/builtins/cpp/ImportMetaObjectBuiltins.cpp b/src/bun.js/builtins/cpp/ImportMetaObjectBuiltins.cpp
index d014618c3..a9ce25b04 100644
--- a/src/bun.js/builtins/cpp/ImportMetaObjectBuiltins.cpp
+++ b/src/bun.js/builtins/cpp/ImportMetaObjectBuiltins.cpp
@@ -255,6 +255,17 @@ const char* const s_importMetaObjectRequireCode =
"})\n" \
;
+const JSC::ConstructAbility s_importMetaObjectMainCodeConstructAbility = JSC::ConstructAbility::CannotConstruct;
+const JSC::ConstructorKind s_importMetaObjectMainCodeConstructorKind = JSC::ConstructorKind::None;
+const JSC::ImplementationVisibility s_importMetaObjectMainCodeImplementationVisibility = JSC::ImplementationVisibility::Public;
+const int s_importMetaObjectMainCodeLength = 52;
+static const JSC::Intrinsic s_importMetaObjectMainCodeIntrinsic = JSC::NoIntrinsic;
+const char* const s_importMetaObjectMainCode =
+ "(function () {\n" \
+ " return this.path === @Bun.main;\n" \
+ "})\n" \
+;
+
#define DEFINE_BUILTIN_GENERATOR(codeName, functionName, overriddenName, argumentCount) \
JSC::FunctionExecutable* codeName##Generator(JSC::VM& vm) \
diff --git a/src/bun.js/builtins/cpp/ImportMetaObjectBuiltins.h b/src/bun.js/builtins/cpp/ImportMetaObjectBuiltins.h
index d47c86980..1a7c5d844 100644
--- a/src/bun.js/builtins/cpp/ImportMetaObjectBuiltins.h
+++ b/src/bun.js/builtins/cpp/ImportMetaObjectBuiltins.h
@@ -67,27 +67,36 @@ extern const int s_importMetaObjectRequireCodeLength;
extern const JSC::ConstructAbility s_importMetaObjectRequireCodeConstructAbility;
extern const JSC::ConstructorKind s_importMetaObjectRequireCodeConstructorKind;
extern const JSC::ImplementationVisibility s_importMetaObjectRequireCodeImplementationVisibility;
+extern const char* const s_importMetaObjectMainCode;
+extern const int s_importMetaObjectMainCodeLength;
+extern const JSC::ConstructAbility s_importMetaObjectMainCodeConstructAbility;
+extern const JSC::ConstructorKind s_importMetaObjectMainCodeConstructorKind;
+extern const JSC::ImplementationVisibility s_importMetaObjectMainCodeImplementationVisibility;
#define WEBCORE_FOREACH_IMPORTMETAOBJECT_BUILTIN_DATA(macro) \
macro(loadCJS2ESM, importMetaObjectLoadCJS2ESM, 1) \
macro(requireESM, importMetaObjectRequireESM, 1) \
macro(internalRequire, importMetaObjectInternalRequire, 1) \
macro(require, importMetaObjectRequire, 1) \
+ macro(main, importMetaObjectMain, 0) \
#define WEBCORE_BUILTIN_IMPORTMETAOBJECT_LOADCJS2ESM 1
#define WEBCORE_BUILTIN_IMPORTMETAOBJECT_REQUIREESM 1
#define WEBCORE_BUILTIN_IMPORTMETAOBJECT_INTERNALREQUIRE 1
#define WEBCORE_BUILTIN_IMPORTMETAOBJECT_REQUIRE 1
+#define WEBCORE_BUILTIN_IMPORTMETAOBJECT_MAIN 1
#define WEBCORE_FOREACH_IMPORTMETAOBJECT_BUILTIN_CODE(macro) \
macro(importMetaObjectLoadCJS2ESMCode, loadCJS2ESM, ASCIILiteral(), s_importMetaObjectLoadCJS2ESMCodeLength) \
macro(importMetaObjectRequireESMCode, requireESM, ASCIILiteral(), s_importMetaObjectRequireESMCodeLength) \
macro(importMetaObjectInternalRequireCode, internalRequire, ASCIILiteral(), s_importMetaObjectInternalRequireCodeLength) \
macro(importMetaObjectRequireCode, require, ASCIILiteral(), s_importMetaObjectRequireCodeLength) \
+ macro(importMetaObjectMainCode, main, "get main"_s, s_importMetaObjectMainCodeLength) \
#define WEBCORE_FOREACH_IMPORTMETAOBJECT_BUILTIN_FUNCTION_NAME(macro) \
macro(internalRequire) \
macro(loadCJS2ESM) \
+ macro(main) \
macro(require) \
macro(requireESM) \
diff --git a/src/bun.js/builtins/cpp/ProcessObjectInternalsBuiltins.cpp b/src/bun.js/builtins/cpp/ProcessObjectInternalsBuiltins.cpp
index c2276138e..bd496deff 100644
--- a/src/bun.js/builtins/cpp/ProcessObjectInternalsBuiltins.cpp
+++ b/src/bun.js/builtins/cpp/ProcessObjectInternalsBuiltins.cpp
@@ -51,7 +51,7 @@ namespace WebCore {
const JSC::ConstructAbility s_processObjectInternalsBindingCodeConstructAbility = JSC::ConstructAbility::CannotConstruct;
const JSC::ConstructorKind s_processObjectInternalsBindingCodeConstructorKind = JSC::ConstructorKind::None;
const JSC::ImplementationVisibility s_processObjectInternalsBindingCodeImplementationVisibility = JSC::ImplementationVisibility::Public;
-const int s_processObjectInternalsBindingCodeLength = 688;
+const int s_processObjectInternalsBindingCodeLength = 709;
static const JSC::Intrinsic s_processObjectInternalsBindingCodeIntrinsic = JSC::NoIntrinsic;
const char* const s_processObjectInternalsBindingCode =
"(function (bindingName) {\n" \
@@ -64,6 +64,9 @@ const char* const s_processObjectInternalsBindingCode =
" var cache = globalThis.Symbol.for(\"process.bindings.constants\");\n" \
" var constants = globalThis[cache];\n" \
" if (!constants) {\n" \
+ " //\n" \
+ " //\n" \
+ " //\n" \
" const {constants: fs} = globalThis[globalThis.Symbol.for(\"Bun.lazy\")](\n" \
" \"createImportMeta\",\n" \
" \"node:process\"\n" \
diff --git a/src/bun.js/builtins/js/ImportMetaObject.js b/src/bun.js/builtins/js/ImportMetaObject.js
index 82701554d..b8d7900c0 100644
--- a/src/bun.js/builtins/js/ImportMetaObject.js
+++ b/src/bun.js/builtins/js/ImportMetaObject.js
@@ -202,4 +202,9 @@ function require(name) {
}
return @internalRequire(@resolveSync(name, from));
-} \ No newline at end of file
+}
+
+@getter
+function main() {
+ return this.path === @Bun.main;
+}
diff --git a/test/js/bun/resolve/import-meta.test.js b/test/js/bun/resolve/import-meta.test.js
index a95b1a0ea..c4bbdb1a6 100644
--- a/test/js/bun/resolve/import-meta.test.js
+++ b/test/js/bun/resolve/import-meta.test.js
@@ -2,6 +2,9 @@ import { it, expect } from "bun:test";
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
import * as Module from "node:module";
import sync from "./require-json.json";
+import { spawnSync } from "bun";
+import { bunEnv, bunExe } from "harness";
+import { join } from "node:path";
const { path, dir } = import.meta;
@@ -9,6 +12,17 @@ it("primordials are not here!", () => {
expect(import.meta.primordials === undefined).toBe(true);
});
+it("import.meta.main", () => {
+ const { exitCode } = spawnSync({
+ cmd: [bunExe(), "run", join(import.meta.dir, "./main-test-script.js")],
+ env: bunEnv,
+ stderr: "inherit",
+ stdout: "inherit",
+ stdin: null,
+ });
+ expect(exitCode).toBe(0);
+});
+
it("import.meta.resolveSync", () => {
expect(import.meta.resolveSync("./" + import.meta.file, import.meta.path)).toBe(path);
const require = Module.createRequire(import.meta.path);
diff --git a/test/js/bun/resolve/main-test-1.js b/test/js/bun/resolve/main-test-1.js
new file mode 100644
index 000000000..8e83d65e1
--- /dev/null
+++ b/test/js/bun/resolve/main-test-1.js
@@ -0,0 +1,5 @@
+if (import.meta.main) {
+ process.exit(1);
+}
+
+export const pass = true;
diff --git a/test/js/bun/resolve/main-test-script.js b/test/js/bun/resolve/main-test-script.js
new file mode 100644
index 000000000..d5b0cb67a
--- /dev/null
+++ b/test/js/bun/resolve/main-test-script.js
@@ -0,0 +1,7 @@
+import "./main-test-1";
+
+if (!import.meta.main) {
+ process.exit(1);
+}
+
+process.exit(0);
diff --git a/test/js/node/fs/fs.test.ts b/test/js/node/fs/fs.test.ts
index fa27ab246..f7b343539 100644
--- a/test/js/node/fs/fs.test.ts
+++ b/test/js/node/fs/fs.test.ts
@@ -38,6 +38,7 @@ import { ReadStream as ReadStreamStar_, WriteStream as WriteStreamStar_ } from "
const Buffer = globalThis.Buffer || Uint8Array;
if (!import.meta.dir) {
+ //@ts-expect-error
import.meta.dir = ".";
}