aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/macros/example.js4
-rw-r--r--examples/macros/mystery-box.tsx15
-rw-r--r--src/feature_flags.zig2
-rw-r--r--src/javascript/jsc/base.zig4
-rw-r--r--src/javascript/jsc/bindings/bindings.cpp11
-rw-r--r--src/javascript/jsc/bindings/bindings.zig19
-rw-r--r--src/javascript/jsc/bindings/headers-cpp.h2
-rw-r--r--src/javascript/jsc/bindings/headers.h5
-rw-r--r--src/javascript/jsc/bindings/headers.zig54
-rw-r--r--src/javascript/jsc/javascript.zig15
-rw-r--r--src/js_ast.zig1982
-rw-r--r--src/js_parser/js_parser.zig78
-rw-r--r--src/js_printer.zig6
-rw-r--r--src/string_immutable.zig8
14 files changed, 1576 insertions, 629 deletions
diff --git a/examples/macros/example.js b/examples/macros/example.js
new file mode 100644
index 000000000..d612c1fa4
--- /dev/null
+++ b/examples/macros/example.js
@@ -0,0 +1,4 @@
+// source code
+import { mysteryBox } from "macro:./mystery-box";
+
+export default "You roll! " + mysteryBox(123);
diff --git a/examples/macros/mystery-box.tsx b/examples/macros/mystery-box.tsx
new file mode 100644
index 000000000..9e72ee1c0
--- /dev/null
+++ b/examples/macros/mystery-box.tsx
@@ -0,0 +1,15 @@
+// macro code:
+export function mysteryBox(node) {
+ const dice = Math.round(Math.random() * 100);
+ if (dice < 25) {
+ return <number value={5} />;
+ } else if (dice < 50) {
+ return <true />;
+ } else if (dice < 75) {
+ return <false />;
+ } else if (dice < 90) {
+ return <string value="a string" />;
+ } else {
+ return <string value={"a very rare string " + dice.toString(10)} />;
+ }
+}
diff --git a/src/feature_flags.zig b/src/feature_flags.zig
index 9aa809879..2819c1cbd 100644
--- a/src/feature_flags.zig
+++ b/src/feature_flags.zig
@@ -69,3 +69,5 @@ pub const remote_inspector = false;
pub const auto_import_buffer = false;
pub const is_macro_enabled = env.isDebug;
+
+pub const force_macro = false;
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig
index 36f00f59e..a5f2d336d 100644
--- a/src/javascript/jsc/base.zig
+++ b/src/javascript/jsc/base.zig
@@ -1539,7 +1539,7 @@ export fn MarkedArrayBuffer_deallocator(bytes_: *c_void, ctx_: *c_void) void {
pub fn castObj(obj: js.JSObjectRef, comptime Type: type) *Type {
return JSPrivateDataPtr.from(js.JSObjectGetPrivate(obj)).as(Type);
}
-const JSExpr = @import("../../js_ast.zig").Macro.JSExpr;
+const JSNode = @import("../../js_ast.zig").Macro.JSNode;
pub const JSPrivateDataPtr = TaggedPointerUnion(.{
ResolveError,
@@ -1550,7 +1550,7 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
Headers,
Body,
Router,
- JSExpr,
+ JSNode,
});
pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type {
diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp
index 50e6978b5..d847a3121 100644
--- a/src/javascript/jsc/bindings/bindings.cpp
+++ b/src/javascript/jsc/bindings/bindings.cpp
@@ -10,6 +10,7 @@
#include <JavaScriptCore/Identifier.h>
#include <JavaScriptCore/IteratorOperations.h>
#include <JavaScriptCore/JSArray.h>
+#include <JavaScriptCore/JSArrayInlines.h>
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/JSCallbackObject.h>
#include <JavaScriptCore/JSClassRef.h>
@@ -51,6 +52,12 @@ JSC__JSValue JSC__JSValue__createEmptyObject(JSC__JSGlobalObject *globalObject,
JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), initialCapacity));
}
+uint32_t JSC__JSValue__getLengthOfArray(JSC__JSValue value, JSC__JSGlobalObject *globalObject) {
+ JSC::JSValue jsValue = JSC::JSValue::decode(value);
+ JSC::JSObject *object = jsValue.toObject(globalObject);
+ return JSC::toLength(globalObject, object);
+}
+
void JSC__JSObject__putRecord(JSC__JSObject *object, JSC__JSGlobalObject *global, ZigString *key,
ZigString *values, size_t valuesLen) {
auto scope = DECLARE_THROW_SCOPE(global->vm());
@@ -220,9 +227,9 @@ JSC__JSValue JSC__Exception__value(JSC__Exception *arg0) {
// JSC__PropertyNameArray__next(JSC__PropertyNameArray* arg0, size_t arg1);
// CPP_DECL void JSC__PropertyNameArray__release(JSC__PropertyNameArray* arg0);
size_t JSC__JSObject__getArrayLength(JSC__JSObject *arg0) { return arg0->getArrayLength(); }
-JSC__JSValue JSC__JSObject__getIndex(JSC__JSObject *arg0, JSC__JSGlobalObject *arg1,
+JSC__JSValue JSC__JSObject__getIndex(JSC__JSValue jsValue, JSC__JSGlobalObject *arg1,
uint32_t arg3) {
- return JSC::JSValue::encode(arg0->getIndex(arg1, arg3));
+ return JSC::JSValue::encode(JSC::JSValue::decode(jsValue).toObject(arg1)->getIndex(arg1, arg3));
}
JSC__JSValue JSC__JSObject__getDirect(JSC__JSObject *arg0, JSC__JSGlobalObject *arg1,
ZigString arg2) {
diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig
index f9cc9bad3..cdc53927a 100644
--- a/src/javascript/jsc/bindings/bindings.zig
+++ b/src/javascript/jsc/bindings/bindings.zig
@@ -41,7 +41,7 @@ pub const JSObject = extern struct {
return create(global, length, creator, Type.call);
}
- pub fn getIndex(this: *JSObject, globalThis: *JSGlobalObject, i: u32) JSValue {
+ pub fn getIndex(this: JSValue, globalThis: *JSGlobalObject, i: u32) JSValue {
return cppFn("getIndex", .{
this,
globalThis,
@@ -1411,6 +1411,17 @@ pub const JSValue = enum(i64) {
});
}
+ pub inline fn toU16(this: JSValue) u36 {
+ return @intCast(u16, this.toInt32());
+ }
+
+ pub fn getLengthOfArray(this: JSValue, globalThis: *JSGlobalObject) u32 {
+ return cppFn("getLengthOfArray", .{
+ this,
+ globalThis,
+ });
+ }
+
pub fn isAggregateError(this: JSValue, globalObject: *JSGlobalObject) bool {
return cppFn("isAggregateError", .{ this, globalObject });
}
@@ -1427,11 +1438,11 @@ pub const JSValue = enum(i64) {
}
pub inline fn asRef(this: JSValue) C_API.JSValueRef {
- return @intToPtr(C_API.JSValueRef, @intCast(usize, @enumToInt(this)));
+ return @intToPtr(C_API.JSValueRef, @bitCast(usize, @enumToInt(this)));
}
pub inline fn fromRef(this: C_API.JSValueRef) JSValue {
- return @intToEnum(JSValue, @intCast(i64, @ptrToInt(this)));
+ return @intToEnum(JSValue, @bitCast(i64, @ptrToInt(this)));
}
pub inline fn asObjectRef(this: JSValue) C_API.JSObjectRef {
@@ -1442,7 +1453,7 @@ pub const JSValue = enum(i64) {
return @intToPtr(*c_void, @intCast(usize, @enumToInt(this)));
}
- pub const Extern = [_][]const u8{ "toZigString", "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "get", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt32", "jsNumberFromInt64", "jsNumberFromUint64", "isUndefined", "isNull", "isUndefinedOrNull", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable" };
+ pub const Extern = [_][]const u8{ "getLengthOfArray", "toZigString", "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "get", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt32", "jsNumberFromInt64", "jsNumberFromUint64", "isUndefined", "isNull", "isUndefinedOrNull", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable" };
};
pub const PropertyName = extern struct {
diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h
index 7ea94d875..63510791c 100644
--- a/src/javascript/jsc/bindings/headers-cpp.h
+++ b/src/javascript/jsc/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1631749917
+//-- AUTOGENERATED FILE -- 1632635195
// clang-format off
#pragma once
diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h
index e40651476..657d4a4f4 100644
--- a/src/javascript/jsc/bindings/headers.h
+++ b/src/javascript/jsc/bindings/headers.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1631749917
+//-- AUTOGENERATED FILE -- 1632635195
// clang-format: off
#pragma once
@@ -234,7 +234,7 @@ typedef void* JSClassRef;
CPP_DECL JSC__JSValue JSC__JSObject__create(JSC__JSGlobalObject* arg0, size_t arg1, void* arg2, void (* ArgFn3)(void* arg0, JSC__JSObject* arg1, JSC__JSGlobalObject* arg2));
CPP_DECL size_t JSC__JSObject__getArrayLength(JSC__JSObject* arg0);
CPP_DECL JSC__JSValue JSC__JSObject__getDirect(JSC__JSObject* arg0, JSC__JSGlobalObject* arg1, ZigString arg2);
-CPP_DECL JSC__JSValue JSC__JSObject__getIndex(JSC__JSObject* arg0, JSC__JSGlobalObject* arg1, uint32_t arg2);
+CPP_DECL JSC__JSValue JSC__JSObject__getIndex(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, uint32_t arg2);
CPP_DECL void JSC__JSObject__putDirect(JSC__JSObject* arg0, JSC__JSGlobalObject* arg1, ZigString arg2, JSC__JSValue JSValue3);
CPP_DECL void JSC__JSObject__putRecord(JSC__JSObject* arg0, JSC__JSGlobalObject* arg1, ZigString* arg2, ZigString* arg3, size_t arg4);
CPP_DECL JSC__JSValue ZigString__toErrorInstance(const ZigString* arg0, JSC__JSGlobalObject* arg1);
@@ -421,6 +421,7 @@ CPP_DECL bool JSC__JSValue__eqlValue(JSC__JSValue JSValue0, JSC__JSValue JSValue
CPP_DECL void JSC__JSValue__forEach(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void (* ArgFn2)(JSC__VM* arg0, JSC__JSGlobalObject* arg1, JSC__JSValue JSValue2));
CPP_DECL void JSC__JSValue__getClassName(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2);
CPP_DECL JSC__JSValue JSC__JSValue__getErrorsProperty(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1);
+CPP_DECL uint32_t JSC__JSValue__getLengthOfArray(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1);
CPP_DECL void JSC__JSValue__getNameProperty(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2);
CPP_DECL JSC__JSValue JSC__JSValue__getPrototype(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1);
CPP_DECL bool JSC__JSValue__isAggregateError(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1);
diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig
index 1b295fbad..a2c111d2d 100644
--- a/src/javascript/jsc/bindings/headers.zig
+++ b/src/javascript/jsc/bindings/headers.zig
@@ -37,69 +37,70 @@ pub const __mbstate_t = extern union {
pub const __darwin_mbstate_t = __mbstate_t;
pub const __darwin_ptrdiff_t = c_long;
pub const __darwin_size_t = c_ulong;
-
+
pub const JSC__RegExpPrototype = struct_JSC__RegExpPrototype;
-
+
pub const JSC__GeneratorPrototype = struct_JSC__GeneratorPrototype;
-
+
pub const JSC__ArrayIteratorPrototype = struct_JSC__ArrayIteratorPrototype;
-
+
pub const JSC__StringPrototype = struct_JSC__StringPrototype;
pub const WTF__StringView = bWTF__StringView;
-
+
pub const JSC__JSPromisePrototype = struct_JSC__JSPromisePrototype;
pub const JSC__CatchScope = bJSC__CatchScope;
pub const JSC__ThrowScope = bJSC__ThrowScope;
pub const JSC__PropertyName = bJSC__PropertyName;
pub const JSC__JSObject = bJSC__JSObject;
pub const WTF__ExternalStringImpl = bWTF__ExternalStringImpl;
-
+
pub const JSC__AsyncIteratorPrototype = struct_JSC__AsyncIteratorPrototype;
pub const WTF__StringImpl = bWTF__StringImpl;
pub const JSC__JSLock = bJSC__JSLock;
pub const JSC__JSModuleLoader = bJSC__JSModuleLoader;
pub const JSC__VM = bJSC__VM;
-
+
pub const JSC__AsyncGeneratorPrototype = struct_JSC__AsyncGeneratorPrototype;
-
+
pub const JSC__AsyncGeneratorFunctionPrototype = struct_JSC__AsyncGeneratorFunctionPrototype;
pub const JSC__JSGlobalObject = bJSC__JSGlobalObject;
pub const JSC__JSFunction = bJSC__JSFunction;
-
+
pub const JSC__ArrayPrototype = struct_JSC__ArrayPrototype;
-
+
pub const JSC__AsyncFunctionPrototype = struct_JSC__AsyncFunctionPrototype;
pub const JSC__Identifier = bJSC__Identifier;
pub const JSC__JSPromise = bJSC__JSPromise;
-
+
pub const JSC__SetIteratorPrototype = struct_JSC__SetIteratorPrototype;
pub const JSC__SourceCode = bJSC__SourceCode;
pub const JSC__JSCell = bJSC__JSCell;
-
+
pub const JSC__BigIntPrototype = struct_JSC__BigIntPrototype;
-
+
pub const JSC__GeneratorFunctionPrototype = struct_JSC__GeneratorFunctionPrototype;
pub const JSC__SourceOrigin = bJSC__SourceOrigin;
pub const JSC__JSModuleRecord = bJSC__JSModuleRecord;
pub const WTF__String = bWTF__String;
pub const WTF__URL = bWTF__URL;
-
+
+
pub const JSC__IteratorPrototype = struct_JSC__IteratorPrototype;
pub const JSC__JSInternalPromise = bJSC__JSInternalPromise;
-
+
pub const JSC__FunctionPrototype = struct_JSC__FunctionPrototype;
pub const Inspector__ScriptArguments = bInspector__ScriptArguments;
pub const JSC__Exception = bJSC__Exception;
pub const JSC__JSString = bJSC__JSString;
-
+
pub const JSC__ObjectPrototype = struct_JSC__ObjectPrototype;
pub const JSC__CallFrame = bJSC__CallFrame;
-
+
pub const JSC__MapIteratorPrototype = struct_JSC__MapIteratorPrototype;
pub extern fn JSC__JSObject__create(arg0: [*c]JSC__JSGlobalObject, arg1: usize, arg2: ?*c_void, ArgFn3: ?fn (?*c_void, [*c]JSC__JSObject, [*c]JSC__JSGlobalObject) callconv(.C) void) JSC__JSValue;
pub extern fn JSC__JSObject__getArrayLength(arg0: [*c]JSC__JSObject) usize;
pub extern fn JSC__JSObject__getDirect(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__JSGlobalObject, arg2: ZigString) JSC__JSValue;
-pub extern fn JSC__JSObject__getIndex(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__JSGlobalObject, arg2: u32) JSC__JSValue;
+pub extern fn JSC__JSObject__getIndex(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: u32) JSC__JSValue;
pub extern fn JSC__JSObject__putDirect(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__JSGlobalObject, arg2: ZigString, JSValue3: JSC__JSValue) void;
pub extern fn JSC__JSObject__putRecord(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]ZigString, arg3: [*c]ZigString, arg4: usize) void;
pub extern fn ZigString__toErrorInstance(arg0: [*c]const ZigString, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
@@ -154,14 +155,14 @@ pub extern fn JSC__JSInternalPromise__then(arg0: [*c]JSC__JSInternalPromise, arg
pub extern fn JSC__SourceOrigin__fromURL(arg0: [*c]const WTF__URL) bJSC__SourceOrigin;
pub extern fn JSC__SourceCode__fromString(arg0: [*c]JSC__SourceCode, arg1: [*c]const WTF__String, arg2: [*c]const JSC__SourceOrigin, arg3: [*c]WTF__String, SourceType4: u8) void;
pub extern fn JSC__JSFunction__calculatedDisplayName(arg0: [*c]JSC__JSFunction, arg1: [*c]JSC__VM) bWTF__String;
-pub extern fn JSC__JSFunction__callWithArguments(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]JSC__JSValue, arg3: usize, arg4: *?*JSC__Exception, arg5: [*c]const u8) JSC__JSValue;
-pub extern fn JSC__JSFunction__callWithArgumentsAndThis(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: [*c]JSC__JSGlobalObject, arg3: [*c]JSC__JSValue, arg4: usize, arg5: *?*JSC__Exception, arg6: [*c]const u8) JSC__JSValue;
-pub extern fn JSC__JSFunction__callWithoutAnyArgumentsOrThis(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: *?*JSC__Exception, arg3: [*c]const u8) JSC__JSValue;
-pub extern fn JSC__JSFunction__callWithThis(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, JSValue2: JSC__JSValue, arg3: *?*JSC__Exception, arg4: [*c]const u8) JSC__JSValue;
-pub extern fn JSC__JSFunction__constructWithArguments(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]JSC__JSValue, arg3: usize, arg4: *?*JSC__Exception, arg5: [*c]const u8) JSC__JSValue;
-pub extern fn JSC__JSFunction__constructWithArgumentsAndNewTarget(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: [*c]JSC__JSGlobalObject, arg3: [*c]JSC__JSValue, arg4: usize, arg5: *?*JSC__Exception, arg6: [*c]const u8) JSC__JSValue;
-pub extern fn JSC__JSFunction__constructWithNewTarget(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, JSValue2: JSC__JSValue, arg3: *?*JSC__Exception, arg4: [*c]const u8) JSC__JSValue;
-pub extern fn JSC__JSFunction__constructWithoutAnyArgumentsOrNewTarget(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: *?*JSC__Exception, arg3: [*c]const u8) JSC__JSValue;
+pub extern fn JSC__JSFunction__callWithArguments(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]JSC__JSValue, arg3: usize, arg4: *?*JSC__Exception , arg5: [*c]const u8) JSC__JSValue;
+pub extern fn JSC__JSFunction__callWithArgumentsAndThis(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: [*c]JSC__JSGlobalObject, arg3: [*c]JSC__JSValue, arg4: usize, arg5: *?*JSC__Exception , arg6: [*c]const u8) JSC__JSValue;
+pub extern fn JSC__JSFunction__callWithoutAnyArgumentsOrThis(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: *?*JSC__Exception , arg3: [*c]const u8) JSC__JSValue;
+pub extern fn JSC__JSFunction__callWithThis(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, JSValue2: JSC__JSValue, arg3: *?*JSC__Exception , arg4: [*c]const u8) JSC__JSValue;
+pub extern fn JSC__JSFunction__constructWithArguments(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]JSC__JSValue, arg3: usize, arg4: *?*JSC__Exception , arg5: [*c]const u8) JSC__JSValue;
+pub extern fn JSC__JSFunction__constructWithArgumentsAndNewTarget(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: [*c]JSC__JSGlobalObject, arg3: [*c]JSC__JSValue, arg4: usize, arg5: *?*JSC__Exception , arg6: [*c]const u8) JSC__JSValue;
+pub extern fn JSC__JSFunction__constructWithNewTarget(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, JSValue2: JSC__JSValue, arg3: *?*JSC__Exception , arg4: [*c]const u8) JSC__JSValue;
+pub extern fn JSC__JSFunction__constructWithoutAnyArgumentsOrNewTarget(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: *?*JSC__Exception , arg3: [*c]const u8) JSC__JSValue;
pub extern fn JSC__JSFunction__createFromNative(arg0: [*c]JSC__JSGlobalObject, arg1: u16, arg2: [*c]const WTF__String, arg3: ?*c_void, ArgFn4: ?fn (?*c_void, [*c]JSC__JSGlobalObject, [*c]JSC__CallFrame) callconv(.C) JSC__JSValue) [*c]JSC__JSFunction;
pub extern fn JSC__JSFunction__displayName(arg0: [*c]JSC__JSFunction, arg1: [*c]JSC__VM) bWTF__String;
pub extern fn JSC__JSFunction__getName(arg0: [*c]JSC__JSFunction, arg1: [*c]JSC__VM) bWTF__String;
@@ -244,6 +245,7 @@ pub extern fn JSC__JSValue__eqlValue(JSValue0: JSC__JSValue, JSValue1: JSC__JSVa
pub extern fn JSC__JSValue__forEach(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, ArgFn2: ?fn ([*c]JSC__VM, [*c]JSC__JSGlobalObject, JSC__JSValue) callconv(.C) void) void;
pub extern fn JSC__JSValue__getClassName(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]ZigString) void;
pub extern fn JSC__JSValue__getErrorsProperty(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
+pub extern fn JSC__JSValue__getLengthOfArray(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) u32;
pub extern fn JSC__JSValue__getNameProperty(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]ZigString) void;
pub extern fn JSC__JSValue__getPrototype(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
pub extern fn JSC__JSValue__isAggregateError(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) bool;
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index 8d7626afb..4dfacffdd 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -36,6 +36,7 @@ pub const GlobalClasses = [_]type{
ResolveError.Class,
Bun.Class,
Fetch.Class,
+ js_ast.Macro.JSNode.BunJSXCallbackFunction,
};
const Blob = @import("../../blob.zig");
@@ -723,6 +724,19 @@ pub const VirtualMachine = struct {
.hash = 0,
.bytecodecache_fd = 0,
};
+ } else if (_specifier.len > js_ast.Macro.namespaceWithColon.len and
+ strings.eqlComptimeIgnoreLen(_specifier[0..js_ast.Macro.namespaceWithColon.len], js_ast.Macro.namespaceWithColon))
+ {
+ if (vm.macro_entry_points.get(MacroEntryPoint.generateIDFromSpecifier(_specifier))) |entry| {
+ return ResolvedSource{
+ .allocator = null,
+ .source_code = ZigString.init(entry.source.contents),
+ .specifier = ZigString.init(_specifier),
+ .source_url = ZigString.init(_specifier),
+ .hash = 0,
+ .bytecodecache_fd = 0,
+ };
+ }
}
const specifier = normalizeSpecifier(_specifier);
@@ -752,6 +766,7 @@ pub const VirtualMachine = struct {
vm.bundler.log = log;
vm.bundler.linker.log = log;
vm.bundler.resolver.log = log;
+
defer {
vm.bundler.log = old;
vm.bundler.linker.log = old;
diff --git a/src/js_ast.zig b/src/js_ast.zig
index c2fafaf07..28512365a 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -1042,6 +1042,8 @@ pub const E = struct {
pub const BigInt = struct {
value: string,
+ pub var empty = BigInt{ .value = "" };
+
pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void {
return try std.json.stringify(self.value, opts, o);
}
@@ -1057,11 +1059,15 @@ pub const E = struct {
pub const Spread = struct { value: ExprNodeIndex };
pub const String = struct {
- value: JavascriptString = &([_]u16{}),
+ value: []const u16 = &.{},
utf8: string = &([_]u8{}),
prefer_template: bool = false,
pub var empty = String{};
+ pub var @"true" = String{ .utf8 = "true" };
+ pub var @"false" = String{ .utf8 = "false" };
+ pub var @"null" = String{ .utf8 = "null" };
+ pub var @"undefined" = String{ .utf8 = "undefined" };
pub fn clone(str: *const String, allocator: *std.mem.Allocator) !String {
if (str.isUTF8()) {
@@ -1102,7 +1108,7 @@ pub const E = struct {
string => {
return strings.eql(s.utf8, other);
},
- JavascriptString => {
+ []u16, []const u16 => {
return strings.utf16EqlString(other, s.utf8);
},
else => {
@@ -1121,7 +1127,7 @@ pub const E = struct {
string => {
return strings.utf16EqlString(s.value, other);
},
- JavascriptString => {
+ []u16, []const u16 => {
return std.mem.eql(u16, other.value, s.value);
},
else => {
@@ -1147,7 +1153,7 @@ pub const E = struct {
return std.hash.Wyhash.hash(0, s.utf8);
} else {
// hash utf-16
- return std.hash.Wyhash.hash(0, @ptrCast([*]u8, s.value.ptr)[0 .. s.value.len * 2]);
+ return std.hash.Wyhash.hash(0, @ptrCast([*]const u8, s.value.ptr)[0 .. s.value.len * 2]);
}
}
@@ -1182,6 +1188,8 @@ pub const E = struct {
pub const RegExp = struct {
value: string,
+ pub var empty = RegExp{ .value = "" };
+
pub fn jsonStringify(self: *const RegExp, opts: anytype, o: anytype) !void {
return try std.json.stringify(self.value, opts, o);
}
@@ -2546,160 +2554,8 @@ pub const Expr = struct {
e_class,
e_require,
- pub inline fn toPublicValue(this: Tag) u16 {
- return @intCast(u16, @enumToInt(this)) + 16;
- }
-
- pub inline fn fromPublicValue(comptime ValueType: type, value: ValueType) ?Tag {
- if (value < 16 or value > @enumToInt(Tag.e_require)) return null;
-
- switch (comptime ValueType) {
- f64 => {
- return @intToEnum(@floatToInt(u16, value - 16), Tag);
- },
- else => {
- return @intToEnum(@intCast(u6, @intCast(u16, value) - 16), Tag);
- },
- }
- }
-
- pub const names_strings = [_]string{
- "<array>",
- "<unary>",
- "<binary>",
- "<boolean>",
- "<super>",
- "<null>",
- "<void>",
- "<new>",
- "<function>",
- "<ntarget>",
- "<import>",
- "<call>",
- "<dot>",
- "<index>",
- "<arrow>",
- "<id>",
- "<importid>",
- "<private>",
- "<jsx>",
- "<missing>",
- "<number>",
- "<bigint>",
- "<object>",
- "<spread>",
- "<string>",
- "<tpart>",
- "<template>",
- "<regexp>",
- "<await>",
- "<yield>",
- "<if>",
- "<resolve>",
- "<import>",
- "<this>",
- "<class>",
- "<require>",
- };
- pub const valid_names_list: string = brk: {
- var names_list = names_strings[0];
- for (names_strings[1..]) |name_str, i| {
- names_list = names_list ++ "\n " ++ name_str;
- }
- break :brk " " ++ names_list;
- };
-
- pub const TagName = std.EnumArray(Tag, string);
-
- pub const names: TagName = brk: {
- var array = TagName.initUndefined();
- array.set(.e_array, names_strings[0]);
- array.set(.e_unary, names_strings[1]);
- array.set(.e_binary, names_strings[2]);
- array.set(.e_boolean, names_strings[3]);
- array.set(.e_super, names_strings[4]);
- array.set(.e_null, names_strings[5]);
- array.set(.e_undefined, names_strings[6]);
- array.set(.e_new, names_strings[7]);
- array.set(.e_function, names_strings[8]);
- array.set(.e_new_target, names_strings[9]);
- array.set(.e_import_meta, names_strings[10]);
- array.set(.e_call, names_strings[11]);
- array.set(.e_dot, names_strings[12]);
- array.set(.e_index, names_strings[13]);
- array.set(.e_arrow, names_strings[14]);
- array.set(.e_identifier, names_strings[15]);
- array.set(.e_import_identifier, names_strings[16]);
- array.set(.e_private_identifier, names_strings[17]);
- array.set(.e_jsx_element, names_strings[18]);
- array.set(.e_missing, names_strings[19]);
- array.set(.e_number, names_strings[20]);
- array.set(.e_big_int, names_strings[21]);
- array.set(.e_object, names_strings[22]);
- array.set(.e_spread, names_strings[23]);
- array.set(.e_string, names_strings[24]);
- array.set(.e_template_part, names_strings[25]);
- array.set(.e_template, names_strings[26]);
- array.set(.e_reg_exp, names_strings[27]);
- array.set(.e_await, names_strings[28]);
- array.set(.e_yield, names_strings[29]);
- array.set(.e_if, names_strings[30]);
- array.set(.e_require_or_require_resolve, names_strings[31]);
- array.set(.e_import, names_strings[32]);
- array.set(.e_this, names_strings[33]);
- array.set(.e_class, names_strings[34]);
- array.set(.e_require, names_strings[35]);
- break :brk array;
- };
- pub const TagExactSizeMatcher = strings.ExactSizeMatcher(8);
- pub fn find(name_: string) ?Tag {
- return switch (TagExactSizeMatcher.match(name_)) {
- TagExactSizeMatcher.case("array") => Tag.e_array,
- TagExactSizeMatcher.case("unary") => Tag.e_unary,
- TagExactSizeMatcher.case("binary") => Tag.e_binary,
- TagExactSizeMatcher.case("boolean") => Tag.e_boolean,
- TagExactSizeMatcher.case("true") => Tag.e_boolean,
- TagExactSizeMatcher.case("false") => Tag.e_boolean,
- TagExactSizeMatcher.case("super") => Tag.e_super,
- TagExactSizeMatcher.case("null") => Tag.e_null,
- TagExactSizeMatcher.case("void") => Tag.e_undefined,
- TagExactSizeMatcher.case("new") => Tag.e_new,
- TagExactSizeMatcher.case("function") => Tag.e_function,
- TagExactSizeMatcher.case("ntarget") => Tag.e_new_target,
- TagExactSizeMatcher.case("imeta") => Tag.e_import_meta,
- TagExactSizeMatcher.case("call") => Tag.e_call,
- TagExactSizeMatcher.case("dot") => Tag.e_dot,
- TagExactSizeMatcher.case("index") => Tag.e_index,
- TagExactSizeMatcher.case("arrow") => Tag.e_arrow,
- TagExactSizeMatcher.case("id") => Tag.e_identifier,
- TagExactSizeMatcher.case("importid") => Tag.e_import_identifier,
- TagExactSizeMatcher.case("jsx") => Tag.e_jsx_element,
- TagExactSizeMatcher.case("missing") => Tag.e_missing,
- TagExactSizeMatcher.case("number") => Tag.e_number,
- TagExactSizeMatcher.case("bigint") => Tag.e_big_int,
- TagExactSizeMatcher.case("object") => Tag.e_object,
- TagExactSizeMatcher.case("spread") => Tag.e_spread,
- TagExactSizeMatcher.case("string") => Tag.e_string,
- TagExactSizeMatcher.case("tpart") => Tag.e_template_part,
- TagExactSizeMatcher.case("template") => Tag.e_template,
- TagExactSizeMatcher.case("regexp") => Tag.e_reg_exp,
- TagExactSizeMatcher.case("await") => Tag.e_await,
- TagExactSizeMatcher.case("yield") => Tag.e_yield,
- TagExactSizeMatcher.case("if") => Tag.e_if,
- TagExactSizeMatcher.case("import") => Tag.e_import,
- TagExactSizeMatcher.case("this") => Tag.e_this,
- TagExactSizeMatcher.case("class") => Tag.e_class,
- TagExactSizeMatcher.case("require") => Tag.e_require,
- else => null,
- };
- }
-
- pub inline fn name(this: Tag) string {
- return names.get(this);
- }
-
pub fn jsonStringify(self: @This(), opts: anytype, o: anytype) !void {
- return try std.json.stringify(self.name(), opts, o);
+ return try std.json.stringify(@tagName(self), opts, o);
}
pub fn isArray(self: Tag) bool {
@@ -3354,7 +3210,7 @@ pub const S = struct {
pub const Comment = struct { text: string };
pub const Directive = struct {
- value: JavascriptString,
+ value: []const u16,
};
pub const ExportClause = struct { items: []ClauseItem, is_single_line: bool = false };
@@ -4211,14 +4067,13 @@ pub const Macro = struct {
replacement: Expr,
};
- pub const JSExpr = struct {
- expr: Expr,
- import_statements: []S.Import = &[_]S.Import{},
-
+ pub const JSNode = struct {
+ loc: logger.Loc,
+ data: Data,
pub const Class = JSCBase.NewClass(
- JSExpr,
+ JSNode,
.{
- .name = "JSExpr",
+ .name = "JSNode",
.read_only = true,
},
.{
@@ -4245,243 +4100,606 @@ pub const Macro = struct {
},
);
- pub const JSNode = struct {
- loc: logger.Loc,
- data: Data,
+ pub fn initExpr(this: Expr) JSNode {
+ switch (this.data) {
+ .e_array => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_array = value } };
+ },
+ .e_unary => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_unary = value } };
+ },
+ .e_binary => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_binary = value } };
+ },
+ .e_function => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_function = value } };
+ },
+ .e_new_target => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_new_target = value } };
+ },
+ .e_import_meta => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_import_meta = value } };
+ },
+ .e_call => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_call = value } };
+ },
+ .e_dot => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_dot = value } };
+ },
+ .e_index => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_index = value } };
+ },
+ .e_arrow => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_arrow = value } };
+ },
+ .e_identifier => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_identifier = value } };
+ },
+ .e_import_identifier => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_import_identifier = value } };
+ },
+ .e_private_identifier => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_private_identifier = value } };
+ },
+ .e_jsx_element => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_jsx_element = value } };
+ },
+ .e_big_int => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_big_int = value } };
+ },
+ .e_object => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_object = value } };
+ },
+ .e_spread => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_spread = value } };
+ },
+ .e_string => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_string = value } };
+ },
+ .e_template_part => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_template_part = value } };
+ },
+ .e_template => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_template = value } };
+ },
+ .e_reg_exp => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_reg_exp = value } };
+ },
+ .e_await => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_await = value } };
+ },
+ .e_yield => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_yield = value } };
+ },
+ .e_if => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_if = value } };
+ },
+ .e_require_or_require_resolve => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_require_or_require_resolve = value } };
+ },
+ .e_import => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_import = value } };
+ },
+ .e_this => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_this = value } };
+ },
+ .e_class => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_class = value } };
+ },
+ .e_require => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_require = value } };
+ },
+ .e_missing => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_missing = value } };
+ },
+ .e_boolean => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_boolean = value } };
+ },
+ .e_super => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_super = value } };
+ },
+ .e_null => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_null = value } };
+ },
+ .e_number => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_number = value } };
+ },
+ .e_undefined => |value| {
+ return JSNode{ .loc = this.loc, .data = .{ .e_undefined = value } };
+ },
+ else => {
+ return JSNode{ .loc = this.loc, .data = .{ .e_missing = .{} } };
+ },
+ }
+ }
- pub fn toExpr(this: JSNode) Expr {
- switch (this.data) {
- .e_array => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_array = value } };
- },
- .e_unary => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_unary = value } };
- },
- .e_binary => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_binary = value } };
- },
- .e_function => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_function = value } };
- },
- .e_new_target => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_new_target = value } };
- },
- .e_import_meta => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_import_meta = value } };
- },
- .e_call => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_call = value } };
- },
- .e_dot => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_dot = value } };
- },
- .e_index => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_index = value } };
- },
- .e_arrow => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_arrow = value } };
- },
- .e_identifier => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_identifier = value } };
- },
- .e_import_identifier => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_import_identifier = value } };
- },
- .e_private_identifier => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_private_identifier = value } };
- },
- .e_jsx_element => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_jsx_element = value } };
- },
- .e_big_int => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_big_int = value } };
- },
- .e_object => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_object = value } };
- },
- .e_spread => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_spread = value } };
- },
- .e_string => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_string = value } };
- },
- .e_template_part => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_template_part = value } };
- },
- .e_template => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_template = value } };
- },
- .e_reg_exp => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_reg_exp = value } };
- },
- .e_await => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_await = value } };
- },
- .e_yield => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_yield = value } };
- },
- .e_if => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_if = value } };
- },
- .e_require_or_require_resolve => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_require_or_require_resolve = value } };
- },
- .e_import => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_import = value } };
- },
- .e_this => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_this = value } };
- },
- .e_class => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_class = value } };
- },
- .e_require => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_require = value } };
- },
- .e_missing => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_missing = value } };
- },
- .e_boolean => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_boolean = value } };
- },
- .e_super => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_super = value } };
- },
- .e_null => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_null = value } };
- },
- .e_number => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_number = value } };
- },
- .e_undefined => |value| {
- return Expr{ .loc = this.loc, .data = .{ .e_undefined = value } };
- },
- wip, .s_import => {
- return Expr{ .loc = this.loc, .data = .{ .e_missing = .{} } };
- },
- }
+ pub fn toExpr(this: JSNode) Expr {
+ switch (this.data) {
+ .e_array => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_array = value } };
+ },
+ .e_unary => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_unary = value } };
+ },
+ .e_binary => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_binary = value } };
+ },
+ .e_function => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_function = value } };
+ },
+ .e_new_target => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_new_target = value } };
+ },
+ .e_import_meta => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_import_meta = value } };
+ },
+ .e_call => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_call = value } };
+ },
+ .e_dot => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_dot = value } };
+ },
+ .e_index => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_index = value } };
+ },
+ .e_arrow => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_arrow = value } };
+ },
+ .e_identifier => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_identifier = value } };
+ },
+ .e_import_identifier => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_import_identifier = value } };
+ },
+ .e_private_identifier => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_private_identifier = value } };
+ },
+ .e_jsx_element => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_jsx_element = value } };
+ },
+ .e_big_int => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_big_int = value } };
+ },
+ .e_object => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_object = value } };
+ },
+ .e_spread => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_spread = value } };
+ },
+ .e_string => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_string = value } };
+ },
+ .e_template_part => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_template_part = value } };
+ },
+ .e_template => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_template = value } };
+ },
+ .e_reg_exp => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_reg_exp = value } };
+ },
+ .e_await => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_await = value } };
+ },
+ .e_yield => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_yield = value } };
+ },
+ .e_if => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_if = value } };
+ },
+ .e_require_or_require_resolve => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_require_or_require_resolve = value } };
+ },
+ .e_import => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_import = value } };
+ },
+ .e_this => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_this = value } };
+ },
+ .e_class => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_class = value } };
+ },
+ .e_require => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_require = value } };
+ },
+ .e_missing => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_missing = value } };
+ },
+ .e_boolean => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_boolean = value } };
+ },
+ .e_super => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_super = value } };
+ },
+ .e_null => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_null = value } };
+ },
+ .e_number => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_number = value } };
+ },
+ .e_undefined => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_undefined = value } };
+ },
+ else => {
+ return Expr{ .loc = this.loc, .data = .{ .e_missing = .{} } };
+ },
}
+ }
- pub const Data = union(Tag) {
- e_array: *E.Array,
- e_unary: *E.Unary,
- e_binary: *E.Binary,
- e_function: *E.Function,
- e_new_target: *E.NewTarget,
- e_import_meta: *E.ImportMeta,
- e_call: *E.Call,
- e_dot: *E.Dot,
- e_index: *E.Index,
- e_arrow: *E.Arrow,
- e_identifier: *E.Identifier,
- e_import_identifier: *E.ImportIdentifier,
- e_private_identifier: *E.PrivateIdentifier,
- e_jsx_element: *E.JsxElement,
-
- e_big_int: *E.BigInt,
- e_object: *E.Object,
- e_spread: *E.Spread,
- e_string: *E.String,
- e_template_part: *E.TemplatePart,
- e_template: *E.Template,
- e_reg_exp: *E.RegExp,
- e_await: *E.Await,
- e_yield: *E.Yield,
- e_if: *E.If,
- e_require_or_require_resolve: *E.RequireOrRequireResolve,
- e_import: *E.Import,
- e_this: *E.This,
- e_class: *E.Class,
- e_require: *E.Require,
-
- s_import: *S.Import,
-
- e_missing: E.Missing,
- e_boolean: E.Boolean,
- e_super: E.Super,
- e_null: E.Null,
- e_number: E.Number,
- e_undefined: E.Undefined,
+ pub const Data = union(Tag) {
+ inline_false: void,
+ inline_true: void,
+ e_boolean: E.Boolean,
+ e_super: E.Super,
+ e_null: E.Null,
+ e_number: E.Number,
+ e_undefined: E.Undefined,
+ e_new_target: E.NewTarget,
+ e_import_meta: E.ImportMeta,
+ e_missing: E.Missing,
+ e_this: E.This,
+
+ e_array: *E.Array,
+ e_unary: *E.Unary,
+ e_binary: *E.Binary,
+ e_function: *E.Function,
+
+ e_call: *E.Call,
+ e_dot: *E.Dot,
+ e_index: *E.Index,
+ e_arrow: *E.Arrow,
+ e_identifier: *E.Identifier,
+ e_import_identifier: *E.ImportIdentifier,
+ e_private_identifier: *E.PrivateIdentifier,
+ e_jsx_element: *E.JSXElement,
+
+ e_big_int: *E.BigInt,
+ e_object: *E.Object,
+ e_spread: *E.Spread,
+ e_string: *E.String,
+ e_template_part: *E.TemplatePart,
+ e_template: *E.Template,
+ e_reg_exp: *E.RegExp,
+ e_await: *E.Await,
+ e_yield: *E.Yield,
+ e_if: *E.If,
+ e_require_or_require_resolve: *E.RequireOrRequireResolve,
+ e_import: *E.Import,
+
+ e_class: *E.Class,
+ e_require: *E.Require,
+
+ s_import: *S.Import,
+ s_block: *S.Block,
+
+ g_property: *G.Property,
+ };
+ pub const Tag = enum(u8) {
+ e_array,
+ e_unary,
+ e_binary,
+ e_function,
+ e_new_target,
+ e_import_meta,
+ e_call,
+ e_dot,
+ e_index,
+ e_arrow,
+ e_identifier,
+ e_import_identifier,
+ e_private_identifier,
+ e_jsx_element,
+ e_big_int,
+ e_object,
+ e_spread,
+ e_string,
+ e_template_part,
+ e_template,
+ e_reg_exp,
+ e_await,
+ e_yield,
+ e_if,
+ e_require_or_require_resolve,
+ e_import,
+ e_this,
+ e_class,
+ e_require,
+ s_import,
+ s_block,
+
+ g_property,
+
+ e_missing,
+ e_boolean,
+ e_super,
+ e_null,
+ e_number,
+ e_undefined,
+
+ inline_true,
+ inline_false,
+
+ pub const ids: std.EnumArray(Tag, Expr.Data) = brk: {
+ var list = std.EnumArray(Tag, Expr.Data).initFill(Expr.Data{ .e_number = E.Number{ .value = 0.0 } });
+ list.set(Tag.e_array, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_array)) },
+ });
+ list.set(Tag.e_unary, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_unary)) },
+ });
+ list.set(Tag.e_binary, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_binary)) },
+ });
+ list.set(Tag.e_boolean, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_boolean)) },
+ });
+ list.set(Tag.e_super, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_super)) },
+ });
+ list.set(Tag.e_null, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_null)) },
+ });
+ list.set(Tag.e_undefined, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_undefined)) },
+ });
+ list.set(Tag.e_function, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_function)) },
+ });
+ list.set(Tag.e_new_target, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_new_target)) },
+ });
+ list.set(Tag.e_import_meta, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_import_meta)) },
+ });
+ list.set(Tag.e_call, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_call)) },
+ });
+ list.set(Tag.e_dot, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_dot)) },
+ });
+ list.set(Tag.e_index, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_index)) },
+ });
+ list.set(Tag.e_arrow, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_arrow)) },
+ });
+ list.set(Tag.e_identifier, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_identifier)) },
+ });
+ list.set(Tag.e_import_identifier, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_import_identifier)) },
+ });
+ list.set(Tag.e_private_identifier, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_private_identifier)) },
+ });
+ list.set(Tag.e_jsx_element, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_jsx_element)) },
+ });
+ list.set(Tag.e_missing, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_missing)) },
+ });
+ list.set(Tag.e_number, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_number)) },
+ });
+ list.set(Tag.e_big_int, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_big_int)) },
+ });
+ list.set(Tag.e_object, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_object)) },
+ });
+ list.set(Tag.e_spread, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_spread)) },
+ });
+ list.set(Tag.e_string, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_string)) },
+ });
+ list.set(Tag.e_template_part, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_template_part)) },
+ });
+ list.set(Tag.e_template, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_template)) },
+ });
+ list.set(Tag.e_reg_exp, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_reg_exp)) },
+ });
+ list.set(Tag.e_await, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_await)) },
+ });
+ list.set(Tag.e_yield, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_yield)) },
+ });
+ list.set(Tag.e_if, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_if)) },
+ });
+ list.set(Tag.e_import, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_import)) },
+ });
+ list.set(Tag.e_this, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_this)) },
+ });
+ list.set(Tag.e_class, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_class)) },
+ });
+ list.set(Tag.e_require, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.e_require)) },
+ });
+ list.set(Tag.s_import, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.s_import)) },
+ });
+ list.set(Tag.g_property, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.g_property)) },
+ });
+ list.set(Tag.s_block, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.s_block)) },
+ });
+ list.set(Tag.inline_true, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.inline_true)) },
+ });
+ list.set(Tag.inline_false, Expr.Data{
+ .e_number = E.Number{ .value = @intToFloat(f64, @enumToInt(Tag.inline_false)) },
+ });
+ break :brk list;
};
- pub const Tag = enum(u8) {
- e_array,
- e_unary,
- e_binary,
- e_boolean,
- e_super,
- e_null,
- e_undefined,
- e_function,
- e_new_target,
- e_import_meta,
- e_call,
- e_dot,
- e_index,
- e_arrow,
- e_identifier,
- e_import_identifier,
- e_private_identifier,
- e_jsx_element,
- e_missing,
- e_number,
- e_big_int,
- e_object,
- e_spread,
- e_string,
- e_template_part,
- e_template,
- e_reg_exp,
- e_await,
- e_yield,
- e_if,
- e_require_or_require_resolve,
- e_import,
- e_this,
- e_class,
- e_require,
- s_import,
-
- wip,
-
- pub const as_expr_tag: std.EnumArray(Tag, Expr.Tag) = brk: {
- var list = std.EnumArray(Tag, Expr.Tag).initFill(Expr.Tag.e_missing);
- list.set(Tag.e_array, Expr.Tag.e_array);
- list.set(Tag.e_unary, Expr.Tag.e_unary);
- list.set(Tag.e_binary, Expr.Tag.e_binary);
- list.set(Tag.e_boolean, Expr.Tag.e_boolean);
- list.set(Tag.e_super, Expr.Tag.e_super);
- list.set(Tag.e_null, Expr.Tag.e_null);
- list.set(Tag.e_undefined, Expr.Tag.e_undefined);
- list.set(Tag.e_function, Expr.Tag.e_function);
- list.set(Tag.e_new_target, Expr.Tag.e_new_target);
- list.set(Tag.e_import_meta, Expr.Tag.e_import_meta);
- list.set(Tag.e_call, Expr.Tag.e_call);
- list.set(Tag.e_dot, Expr.Tag.e_dot);
- list.set(Tag.e_index, Expr.Tag.e_index);
- list.set(Tag.e_arrow, Expr.Tag.e_arrow);
- list.set(Tag.e_identifier, Expr.Tag.e_identifier);
- list.set(Tag.e_import_identifier, Expr.Tag.e_import_identifier);
- list.set(Tag.e_private_identifier, Expr.Tag.e_private_identifier);
- list.set(Tag.e_jsx_element, Expr.Tag.e_jsx_element);
- list.set(Tag.e_missing, Expr.Tag.e_missing);
- list.set(Tag.e_number, Expr.Tag.e_number);
- list.set(Tag.e_big_int, Expr.Tag.e_big_int);
- list.set(Tag.e_object, Expr.Tag.e_object);
- list.set(Tag.e_spread, Expr.Tag.e_spread);
- list.set(Tag.e_string, Expr.Tag.e_string);
- list.set(Tag.e_template_part, Expr.Tag.e_template_part);
- list.set(Tag.e_template, Expr.Tag.e_template);
- list.set(Tag.e_reg_exp, Expr.Tag.e_reg_exp);
- list.set(Tag.e_await, Expr.Tag.e_await);
- list.set(Tag.e_yield, Expr.Tag.e_yield);
- list.set(Tag.e_if, Expr.Tag.e_if);
- list.set(Tag.e_require_or_require_resolve, Expr.Tag.e_require_or_require_resolve);
- list.set(Tag.e_import, Expr.Tag.e_import);
- list.set(Tag.e_this, Expr.Tag.e_this);
- list.set(Tag.e_class, Expr.Tag.e_class);
- list.set(Tag.e_require, Expr.Tag.e_require);
- break :brk list;
- };
+
+ pub const names = std.ComptimeStringMap(Tag, .{
+ .{ "array", Tag.e_array },
+ .{ "unary", Tag.e_unary },
+ .{ "binary", Tag.e_binary },
+ .{ "bool", Tag.e_boolean },
+ .{ "super", Tag.e_super },
+ .{ "null", Tag.e_null },
+ .{ "undefined", Tag.e_undefined },
+ .{ "function", Tag.e_function },
+ .{ "new_target", Tag.e_new_target },
+ .{ "import_meta", Tag.e_import_meta },
+ .{ "call", Tag.e_call },
+ .{ "dot", Tag.e_dot },
+ .{ "index", Tag.e_index },
+ .{ "arrow", Tag.e_arrow },
+ .{ "id", Tag.e_identifier },
+ .{ "import-id", Tag.e_import_identifier },
+ .{ "private-id", Tag.e_private_identifier },
+ .{ "jsx", Tag.e_jsx_element },
+ .{ "missing", Tag.e_missing },
+ .{ "number", Tag.e_number },
+ .{ "bigint", Tag.e_big_int },
+ .{ "object", Tag.e_object },
+ .{ "spread", Tag.e_spread },
+ .{ "string", Tag.e_string },
+ .{ "template-part", Tag.e_template_part },
+ .{ "template", Tag.e_template },
+ .{ "regex", Tag.e_reg_exp },
+ .{ "await", Tag.e_await },
+ .{ "yield", Tag.e_yield },
+ .{ "if", Tag.e_if },
+ .{ "dynamic", Tag.e_import },
+ .{ "this", Tag.e_this },
+ .{ "class", Tag.e_class },
+ .{ "require", Tag.e_require },
+ .{ "import", Tag.s_import },
+ .{ "property", Tag.g_property },
+ .{ "block", Tag.s_block },
+ .{ "true", Tag.inline_true },
+ .{ "false", Tag.inline_false },
+ });
+
+ pub const as_expr_tag: std.EnumArray(Tag, Expr.Tag) = brk: {
+ var list = std.EnumArray(Tag, Expr.Tag).initFill(Expr.Tag.e_missing);
+ list.set(Tag.e_array, Expr.Tag.e_array);
+ list.set(Tag.e_unary, Expr.Tag.e_unary);
+ list.set(Tag.e_binary, Expr.Tag.e_binary);
+ list.set(Tag.e_boolean, Expr.Tag.e_boolean);
+ list.set(Tag.e_super, Expr.Tag.e_super);
+ list.set(Tag.e_null, Expr.Tag.e_null);
+ list.set(Tag.e_undefined, Expr.Tag.e_undefined);
+ list.set(Tag.e_function, Expr.Tag.e_function);
+ list.set(Tag.e_new_target, Expr.Tag.e_new_target);
+ list.set(Tag.e_import_meta, Expr.Tag.e_import_meta);
+ list.set(Tag.e_call, Expr.Tag.e_call);
+ list.set(Tag.e_dot, Expr.Tag.e_dot);
+ list.set(Tag.e_index, Expr.Tag.e_index);
+ list.set(Tag.e_arrow, Expr.Tag.e_arrow);
+ list.set(Tag.e_identifier, Expr.Tag.e_identifier);
+ list.set(Tag.e_import_identifier, Expr.Tag.e_import_identifier);
+ list.set(Tag.e_private_identifier, Expr.Tag.e_private_identifier);
+ list.set(Tag.e_jsx_element, Expr.Tag.e_jsx_element);
+ list.set(Tag.e_missing, Expr.Tag.e_missing);
+ list.set(Tag.e_number, Expr.Tag.e_number);
+ list.set(Tag.e_big_int, Expr.Tag.e_big_int);
+ list.set(Tag.e_object, Expr.Tag.e_object);
+ list.set(Tag.e_spread, Expr.Tag.e_spread);
+ list.set(Tag.e_string, Expr.Tag.e_string);
+ list.set(Tag.e_template_part, Expr.Tag.e_template_part);
+ list.set(Tag.e_template, Expr.Tag.e_template);
+ list.set(Tag.e_reg_exp, Expr.Tag.e_reg_exp);
+ list.set(Tag.e_await, Expr.Tag.e_await);
+ list.set(Tag.e_yield, Expr.Tag.e_yield);
+ list.set(Tag.e_if, Expr.Tag.e_if);
+ list.set(Tag.e_require_or_require_resolve, Expr.Tag.e_require_or_require_resolve);
+ list.set(Tag.e_import, Expr.Tag.e_import);
+ list.set(Tag.e_this, Expr.Tag.e_this);
+ list.set(Tag.e_class, Expr.Tag.e_class);
+ list.set(Tag.e_require, Expr.Tag.e_require);
+ break :brk list;
+ };
+
+ pub const to_expr_tag: std.EnumArray(Expr.Tag, Tag) = brk: {
+ var list = std.EnumArray(Expr.Tag, Tag).initFill(Tag.wip);
+ list.set(Expr.Tag.e_array, Tag.e_array);
+ list.set(Expr.Tag.e_unary, Tag.e_unary);
+ list.set(Expr.Tag.e_binary, Tag.e_binary);
+ list.set(Expr.Tag.e_boolean, Tag.e_boolean);
+ list.set(Expr.Tag.e_super, Tag.e_super);
+ list.set(Expr.Tag.e_null, Tag.e_null);
+ list.set(Expr.Tag.e_undefined, Tag.e_undefined);
+ list.set(Expr.Tag.e_function, Tag.e_function);
+ list.set(Expr.Tag.e_new_target, Tag.e_new_target);
+ list.set(Expr.Tag.e_import_meta, Tag.e_import_meta);
+ list.set(Expr.Tag.e_call, Tag.e_call);
+ list.set(Expr.Tag.e_dot, Tag.e_dot);
+ list.set(Expr.Tag.e_index, Tag.e_index);
+ list.set(Expr.Tag.e_arrow, Tag.e_arrow);
+ list.set(Expr.Tag.e_identifier, Tag.e_identifier);
+ list.set(Expr.Tag.e_import_identifier, Tag.e_import_identifier);
+ list.set(Expr.Tag.e_private_identifier, Tag.e_private_identifier);
+ list.set(Expr.Tag.e_jsx_element, Tag.e_jsx_element);
+ list.set(Expr.Tag.e_missing, Tag.e_missing);
+ list.set(Expr.Tag.e_number, Tag.e_number);
+ list.set(Expr.Tag.e_big_int, Tag.e_big_int);
+ list.set(Expr.Tag.e_object, Tag.e_object);
+ list.set(Expr.Tag.e_spread, Tag.e_spread);
+ list.set(Expr.Tag.e_string, Tag.e_string);
+ list.set(Expr.Tag.e_template_part, Tag.e_template_part);
+ list.set(Expr.Tag.e_template, Tag.e_template);
+ list.set(Expr.Tag.e_reg_exp, Tag.e_reg_exp);
+ list.set(Expr.Tag.e_await, Tag.e_await);
+ list.set(Expr.Tag.e_yield, Tag.e_yield);
+ list.set(Expr.Tag.e_if, Tag.e_if);
+ list.set(Expr.Tag.e_require_or_require_resolve, Tag.e_require_or_require_resolve);
+ list.set(Expr.Tag.e_import, Tag.e_import);
+ list.set(Expr.Tag.e_this, Tag.e_this);
+ list.set(Expr.Tag.e_class, Tag.e_class);
+ list.set(Expr.Tag.e_require, Tag.e_require);
+ break :brk list;
+ };
+
+ pub const Validator = struct {
+ pub const List = std.EnumArray(JSNode.Tag, bool);
+ fn NewList(comptime valid_tags: anytype) List {
+ return comptime brk: {
+ var list = List.initFill(false);
+ for (std.meta.fieldNames(@TypeOf(valid_tags))) |index| {
+ const name = @tagName(@field(valid_tags, index));
+
+ if (!@hasField(JSNode.Tag, name)) {
+ @compileError(
+ "JSNode.Tag does not have a \"" ++ name ++ "\" field. Valid fields are " ++ std.fmt.comptimePrint(
+ "{s}",
+ .{
+ std.meta.fieldNames(@TypeOf(valid_tags)),
+ },
+ ),
+ );
+ }
+ list.set(@field(JSNode.Tag, name), true);
+ }
+
+ break :brk list;
+ };
+ }
+
+ pub const valid_object_tags = Tag.Validator.NewList(.{
+ .g_property,
+ .e_spread,
+ .e_identifier,
+ .e_import_identifier,
+ .e_index,
+ .e_call,
+ .e_private_identifier,
+ .e_dot,
+ .e_unary,
+ .e_binary,
+ });
};
pub const max_tag: u8 = brk: {
@@ -4503,6 +4721,563 @@ pub const Macro = struct {
};
};
+ pub fn NewJSXWriter(comptime P: type) type {
+ return struct {
+ const JSXWriter = @This();
+ p: *P,
+ bun_jsx_ref: Ref,
+ log: *logger.Log,
+ args: ExprList,
+ bun_identifier: *E.Identifier,
+ allocator: *std.mem.Allocator,
+ parent_tag: Tag = Tag.e_missing,
+
+ pub fn initWriter(p: *P, bun_identifier: *E.Identifier) JSXWriter {
+ return JSXWriter{
+ .p = p,
+ .log = p.log,
+ .bun_jsx_ref = p.bun_jsx_ref,
+ .args = ExprList.init(p.allocator),
+ .allocator = p.allocator,
+ .bun_identifier = bun_identifier,
+ };
+ }
+
+ fn hasPropertyNamed(props: []G.Property, comptime name: string) bool {
+ return indexOfPropertyByName(props, name) != null;
+ }
+
+ fn indexOfPropertyByName(props: []G.Property, comptime name: string) ?u32 {
+ for (props) |prop, i| {
+ const key = prop.key orelse continue;
+ if (key.data != .e_string or !key.data.e_string.isUTF8()) continue;
+ if (strings.eqlComptime(key.data.e_string.utf8, name)) return @intCast(u32, i);
+ }
+
+ return null;
+ }
+
+ fn propertyValueNamed(props: []G.Property, comptime name: string) ?Expr {
+ for (props) |prop| {
+ const key = prop.key orelse continue;
+ if (key.data != .e_string or !key.data.e_string.isUTF8()) continue;
+ if (strings.eqlComptime(key.data.e_string.utf8, name)) return prop.value;
+ }
+
+ return null;
+ }
+
+ pub fn writeExprType(self: *JSXWriter, expr: Expr) bool {}
+
+ pub fn writeNodeType(self: *JSXWriter, tag: JSNode.Tag, props: []G.Property, children: []Expr, loc: logger.Loc) bool {
+ switch (tag) {
+
+ // <bool value={foo} />
+ // intended for dynamic values
+ Tag.e_boolean => {
+ self.args.ensureUnusedCapacity(2) catch unreachable;
+ self.args.appendAssumeCapacity(Expr{ .loc = loc, .data = comptime Tag.ids.get(Tag.e_boolean) });
+ const value_i = indexOfPropertyByName(props, "value") orelse {
+ self.log.addError(self.p.source, loc, "<bool> should have a \"value\" prop") catch unreachable;
+ self.args.append(Expr{ .data = .{ .e_boolean = .{ .value = true } }, .loc = loc }) catch unreachable;
+ return true;
+ };
+ const value = props[value_i].value orelse Expr{ .data = .{ .e_boolean = .{ .value = true } }, .loc = loc };
+
+ switch (value.data) {
+ .e_jsx_element => |el| {
+ return self.writeElement(el.*);
+ },
+ .e_string => {
+ self.log.addError(self.p.source, value.loc, "\"value\" shouldn't be a string") catch unreachable;
+ self.args.appendAssumeCapacity(Expr{ .data = .{ .e_boolean = .{ .value = true } }, .loc = value.loc });
+ },
+ .e_boolean => {
+ self.args.appendAssumeCapacity(value);
+ },
+ .e_missing => {
+ self.args.appendAssumeCapacity(Expr{ .data = .{ .e_boolean = .{ .value = true } }, .loc = value.loc });
+ },
+ // null and undefined literals are coerced to false
+ .e_null, .e_undefined => {
+ self.args.appendAssumeCapacity(Expr{ .data = .{ .e_boolean = .{ .value = false } }, .loc = value.loc });
+ },
+ .e_number => {
+ // Numbers are cooerced to booleans
+ self.args.appendAssumeCapacity(Expr{ .data = .{ .e_boolean = .{ .value = value.data.e_number.value > 0.0 } }, .loc = value.loc });
+ },
+ // these ones are not statically analyzable so we just leave them in as-is
+ .e_if, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ self.args.appendAssumeCapacity(self.p.visitExpr(value));
+ },
+ // everything else is invalid
+ else => {
+ self.log.addError(self.p.source, value.loc, "\"value\" should be a bool, jsx element, number, identifier, index, call, private identifier, or dot") catch unreachable;
+ self.args.appendAssumeCapacity(Expr{ .data = .{ .e_boolean = .{ .value = false } }, .loc = value.loc });
+ },
+ }
+
+ return true;
+ },
+ // <number value={1.0} />
+ Tag.e_number => {
+ self.args.ensureUnusedCapacity(2) catch unreachable;
+ self.args.appendAssumeCapacity(Expr{ .loc = loc, .data = comptime Tag.ids.get(Tag.e_number) });
+ const invalid_value = Expr{ .data = .{ .e_number = .{ .value = 0.0 } }, .loc = loc };
+ const value_i = indexOfPropertyByName(props, "value") orelse {
+ self.log.addError(self.p.source, loc, "<number> should have a \"value\" prop") catch unreachable;
+ self.args.append(invalid_value) catch unreachable;
+ return true;
+ };
+ const value = props[value_i].value orelse invalid_value;
+
+ switch (value.data) {
+ .e_jsx_element => |el| {
+ return self.writeElement(el.*);
+ },
+ .e_string => {
+ self.log.addError(self.p.source, loc, "<number> should not be a string.") catch unreachable;
+ self.args.appendAssumeCapacity(invalid_value);
+ },
+ .e_boolean => {
+ // Booleans are cooerced to numbers
+ self.args.appendAssumeCapacity(
+ Expr{
+ .data = .{
+ .e_number = E.Number{
+ .value = @intToFloat(f64, @boolToInt(value.data.e_boolean.value)),
+ },
+ },
+ .loc = value.loc,
+ },
+ );
+ },
+ .e_missing => {
+ self.args.appendAssumeCapacity(invalid_value);
+ },
+ // null and undefined literals are coerced to 0
+ .e_null, .e_undefined => {
+ self.args.appendAssumeCapacity(Expr{ .data = .{ .e_number = .{ .value = 0 } }, .loc = value.loc });
+ },
+ // <number>123</number>
+ .e_number => {
+ // Numbers are cooerced to booleans
+ self.args.appendAssumeCapacity(value);
+ },
+ // these ones are not statically analyzable so we just leave them in as-is
+ .e_if, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ self.args.appendAssumeCapacity(self.p.visitExpr(value));
+ },
+ // everything else is invalid
+ else => {
+ self.log.addError(self.p.source, value.loc, "<number value> should be a number, jsx element, identifier, index, call, private identifier, or dot expression") catch unreachable;
+ self.args.appendAssumeCapacity(invalid_value);
+ },
+ }
+
+ return true;
+ },
+ Tag.e_big_int => {
+ self.args.ensureUnusedCapacity(2) catch unreachable;
+ self.args.appendAssumeCapacity(Expr{ .loc = loc, .data = comptime Tag.ids.get(Tag.e_big_int) });
+ const invalid_value = Expr{ .data = .{ .e_big_int = &E.BigInt.empty }, .loc = loc };
+ const value_i = indexOfPropertyByName(props, "value") orelse {
+ self.log.addError(self.p.source, loc, "<big-int> should have a \"value\" prop") catch unreachable;
+ self.args.append(invalid_value) catch unreachable;
+ return true;
+ };
+ const value = props[value_i].value orelse invalid_value;
+
+ switch (value.data) {
+ .e_jsx_element => |el| {
+ return self.writeElement(el.*);
+ },
+ .e_string => |str| {
+ self.args.appendAssumeCapacity(Expr.alloc(self.allocator, E.BigInt, E.BigInt{ .value = std.mem.trimRight(u8, str.utf8, "n") }, value.loc));
+ },
+ .e_big_int => |bigint| {
+ self.args.appendAssumeCapacity(value);
+ },
+ .e_missing => {
+ self.args.appendAssumeCapacity(invalid_value);
+ },
+ // null and undefined literals are coerced to 0
+ .e_null, .e_undefined => {
+ self.args.appendAssumeCapacity(Expr{ .data = .{ .e_big_int = &E.BigInt.empty }, .loc = value.loc });
+ },
+ // these ones are not statically analyzable so we just leave them in as-is
+ .e_if, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ self.args.appendAssumeCapacity(self.p.visitExpr(value));
+ },
+ // everything else is invalid
+ else => {
+ self.log.addError(self.p.source, value.loc, "\"value\" should be a BigInt, jsx element, identifier, index, call, private identifier, or dot expression") catch unreachable;
+ self.args.appendAssumeCapacity(invalid_value);
+ },
+ }
+
+ return true;
+ },
+ Tag.e_array => {
+ self.args.ensureUnusedCapacity(2 + children.len) catch unreachable;
+ self.args.appendAssumeCapacity(Expr{ .loc = loc, .data = comptime Tag.ids.get(Tag.e_array) });
+ const children_count = @truncate(u16, children.len);
+ self.args.appendAssumeCapacity(Expr{ .loc = loc, .data = .{ .e_number = E.Number{ .value = @intToFloat(f64, children_count) } } });
+
+ var old_parent = self.parent_tag;
+ self.parent_tag = Tag.e_array;
+ defer self.parent_tag = old_parent;
+ for (children) |child, i| {
+ switch (child.data) {
+ .e_jsx_element => |el| {
+ if (!self.writeElement(el.*)) return false;
+ },
+ // TODO: handle when simplification changes the expr type
+ .e_spread, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ const visited_expr = self.p.visitExpr(child);
+ switch (visited_expr.data) {
+ .e_jsx_element => |el| {
+ if (!self.writeElement(el.*)) return false;
+ },
+ .e_if, .e_spread, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ self.args.append(visited_expr) catch unreachable;
+ },
+ else => {
+ self.log.addError(self.p.source, visited_expr.loc, "<array> should only contain other jsx elements") catch unreachable;
+ self.args.append(Expr{ .data = .{ .e_missing = E.Missing{} }, .loc = visited_expr.loc }) catch unreachable;
+ },
+ }
+ },
+ else => {
+ self.log.addError(self.p.source, child.loc, "<array> should only contain other jsx elements") catch unreachable;
+ self.args.append(Expr{ .data = .{ .e_missing = E.Missing{} }, .loc = child.loc }) catch unreachable;
+ },
+ }
+ }
+
+ return true;
+ },
+ Tag.e_object => {
+ self.args.ensureUnusedCapacity(2 + children.len) catch unreachable;
+ self.args.appendAssumeCapacity(Expr{ .loc = loc, .data = comptime Tag.ids.get(Tag.e_object) });
+ const children_count = @truncate(u16, children.len);
+ self.args.appendAssumeCapacity(Expr{ .loc = loc, .data = .{ .e_number = E.Number{ .value = @intToFloat(f64, children_count) } } });
+
+ var old_parent = self.parent_tag;
+ self.parent_tag = Tag.e_object;
+ defer self.parent_tag = old_parent;
+
+ for (children) |child, i| {
+ switch (child.data) {
+ .e_jsx_element => |el| {
+ if (!self.writeElementWithValidTagList(el.*, comptime Tag.Validator.valid_object_tags)) return false;
+ },
+ .e_if, .e_spread, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ const visited = self.p.visitExpr(child);
+ switch (visited.data) {
+ .e_jsx_element => |el| {
+ if (!self.writeElementWithValidTagList(el.*, comptime Tag.Validator.valid_object_tags)) return false;
+ },
+ .e_if, .e_spread, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ self.args.append(visited) catch unreachable;
+ },
+ else => {
+ self.log.addError(self.p.source, child.loc, "<object> should only contain other jsx elements") catch unreachable;
+ self.args.append(Expr{ .data = .{ .e_missing = E.Missing{} }, .loc = child.loc }) catch unreachable;
+ },
+ }
+ },
+ else => {
+ self.log.addError(self.p.source, child.loc, "<object> should only contain other jsx elements") catch unreachable;
+ self.args.append(Expr{ .data = .{ .e_missing = E.Missing{} }, .loc = child.loc }) catch unreachable;
+ },
+ }
+ }
+
+ return true;
+ },
+
+ Tag.g_property => {
+ const name_property = propertyValueNamed(props, "name");
+ const value_property = propertyValueNamed(props, "value");
+ const init_property = propertyValueNamed(props, "init");
+
+ var old_parent = self.parent_tag;
+ if (old_parent != .e_object) {
+ self.args.append(Expr{ .loc = loc, .data = comptime Tag.ids.get(Tag.g_property) }) catch unreachable;
+ }
+
+ self.parent_tag = Tag.g_property;
+ defer self.parent_tag = old_parent;
+
+ var is_spread = false;
+ if (value_property) |prop| {
+ switch (prop.data) {
+ .e_jsx_element => |el| {
+ if (!self.writeElement(el.*)) return false;
+ },
+ .e_if, .e_spread, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ self.args.append(self.p.visitExpr(prop)) catch unreachable;
+ },
+ else => {
+ self.log.addError(self.p.source, prop.loc, "value should only contain other jsx elements") catch unreachable;
+ self.args.append(Expr{ .data = .{ .e_missing = E.Missing{} }, .loc = prop.loc }) catch unreachable;
+ },
+ }
+ } else {
+ self.args.append(Expr{ .data = comptime Tag.ids.get(.e_undefined), .loc = loc }) catch unreachable;
+ }
+
+ if (init_property) |prop| {
+ switch (prop.data) {
+ .e_jsx_element => |el| {
+ if (!self.writeElement(el.*)) return false;
+ },
+
+ .e_spread, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ self.args.append(self.p.visitExpr(prop)) catch unreachable;
+ },
+ else => {
+ self.log.addError(self.p.source, prop.loc, "init should only contain other jsx elements") catch unreachable;
+ self.args.append(Expr{ .data = .{ .e_missing = E.Missing{} }, .loc = prop.loc }) catch unreachable;
+ },
+ }
+ } else {
+ self.args.append(Expr{ .data = comptime Tag.ids.get(.e_undefined), .loc = loc }) catch unreachable;
+ }
+
+ if (name_property) |prop| {
+ switch (prop.data) {
+ .e_jsx_element => |el| {
+ if (!self.writeElement(el.*)) return false;
+ },
+ .e_string => |str| {
+ self.args.append(prop) catch unreachable;
+ },
+ .e_if, .e_spread, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ self.args.append(self.p.visitExpr(prop)) catch unreachable;
+ },
+ else => {
+ self.log.addError(self.p.source, prop.loc, "should only contain other jsx elements or a string") catch unreachable;
+ self.args.append(Expr{ .data = .{ .e_missing = E.Missing{} }, .loc = prop.loc }) catch unreachable;
+ },
+ }
+ }
+
+ return true;
+ },
+ Tag.e_string => {
+ self.args.ensureUnusedCapacity(2) catch unreachable;
+ self.args.appendAssumeCapacity(Expr{ .loc = loc, .data = comptime Tag.ids.get(Tag.e_string) });
+ const invalid_value = Expr{ .data = .{ .e_string = &E.String.empty }, .loc = loc };
+ const value_i = indexOfPropertyByName(props, "value") orelse {
+ self.log.addError(self.p.source, loc, "<string> should have a \"value\" prop") catch unreachable;
+ self.args.append(invalid_value) catch unreachable;
+ return true;
+ };
+ const value = props[value_i].value orelse invalid_value;
+
+ switch (value.data) {
+ .e_jsx_element => |el| {
+ return self.writeElement(el.*);
+ },
+ .e_string => {
+ self.args.appendAssumeCapacity(value);
+ },
+ .e_missing => {
+ self.args.appendAssumeCapacity(invalid_value);
+ },
+ // null is cooerced to "null"
+ .e_null => {
+ self.args.appendAssumeCapacity(Expr{ .loc = value.loc, .data = .{ .e_string = &E.String.@"null" } });
+ },
+ // undefined is cooerced to "undefined"
+ .e_undefined => {
+ self.args.appendAssumeCapacity(Expr{ .loc = value.loc, .data = .{ .e_string = &E.String.@"undefined" } });
+ },
+ .e_boolean => |boolean| {
+ self.args.appendAssumeCapacity(Expr{ .loc = value.loc, .data = .{ .e_string = if (boolean.value) &E.String.@"true" else &E.String.@"false" } });
+ },
+ // these ones are not statically analyzable so we just leave them in as-is
+ .e_if, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ self.args.appendAssumeCapacity(self.p.visitExpr(value));
+ },
+ // everything else is invalid
+ else => {
+ self.log.addError(self.p.source, value.loc, "<string value> should be a string, jsx element, identifier, index, call, private identifier, or dot expression") catch unreachable;
+ self.args.appendAssumeCapacity(invalid_value);
+ },
+ }
+ },
+ Tag.e_reg_exp => {
+ self.args.ensureUnusedCapacity(2) catch unreachable;
+ self.args.appendAssumeCapacity(Expr{ .loc = loc, .data = comptime Tag.ids.get(Tag.e_reg_exp) });
+ const invalid_value = Expr{ .data = .{ .e_reg_exp = &E.RegExp.empty }, .loc = loc };
+
+ const value_i = indexOfPropertyByName(props, "value") orelse {
+ self.log.addError(self.p.source, loc, "<regex> should have a \"value\" prop") catch unreachable;
+ self.args.append(invalid_value) catch unreachable;
+ return true;
+ };
+
+ const value = props[value_i].value orelse invalid_value;
+
+ switch (value.data) {
+ .e_string => |str| {
+ self.args.appendAssumeCapacity(Expr.alloc(self.allocator, E.RegExp, E.RegExp{ .value = str.utf8 }, value.loc));
+ },
+ .e_reg_exp => {
+ self.args.appendAssumeCapacity(value);
+ },
+ .e_missing, .e_null, .e_undefined => {
+ self.args.appendAssumeCapacity(invalid_value);
+ },
+ // these ones are not statically analyzable so we just leave them in as-is
+ .e_if, .e_identifier, .e_import_identifier, .e_index, .e_call, .e_private_identifier, .e_dot, .e_unary, .e_binary => {
+ self.args.appendAssumeCapacity(self.p.visitExpr(value));
+ },
+ // everything else is invalid
+ else => {
+ self.log.addError(self.p.source, value.loc, "<regex value> should be a string, jsx element, identifier, index, call, private identifier, or dot expression") catch unreachable;
+ self.args.appendAssumeCapacity(invalid_value);
+ },
+ }
+
+ return true;
+ },
+ // Tag.e_jsx_element => unreachable,
+ // Tag.e_identifier => {
+ // // self.args.ensureUnusedCapacity(2) catch unreachable;
+ // Global.notimpl();
+ // },
+ // Tag.e_import_identifier => {
+ // Global.notimpl();
+ // },
+ // Tag.e_private_identifier => {
+ // Global.notimpl();
+ // },
+
+ // Tag.e_unary => {
+
+ // },
+ // Tag.e_binary => {},
+
+ // Tag.e_function => {},
+ // Tag.e_new_target => {},
+ // Tag.e_import_meta => {},
+ // Tag.e_call => {},
+ // Tag.e_dot => {},
+ // Tag.e_index => {},
+ // Tag.e_arrow => {},
+
+ // Tag.e_spread => {},
+
+ // Tag.e_template_part => {},
+ // Tag.e_template => {},
+ // Tag.e_regex => {},
+ // Tag.e_await => {},
+ // Tag.e_yield => {},
+ // Tag.e_if => {},
+ // Tag.e_import => {},
+
+ // Tag.e_class => {},
+ // Tag.e_require => {},
+ // Tag.s_import => {},
+
+ // Tag.s_block => {},
+
+ // The valueless ones
+ Tag.e_super, Tag.e_null, Tag.e_undefined, Tag.e_missing, Tag.inline_true, Tag.inline_false, Tag.e_this => {
+ self.args.append(Expr{ .loc = loc, .data = Tag.ids.get(tag) }) catch unreachable;
+ },
+ else => Global.panic("Tag \"{s}\" is not implemented yet.", .{@tagName(tag)}),
+ }
+
+ return true;
+ }
+
+ pub fn writeFunctionCall(self: *JSXWriter, element: E.JSXElement) Expr {
+ if (element.tag) |tag_expr| {
+ switch (tag_expr.data) {
+ .e_string => |str| {
+ self.p.recordUsage(self.bun_jsx_ref);
+ _ = self.writeElement(element);
+ var call_args = self.p.allocator.alloc(Expr, 1) catch unreachable;
+ call_args[0] = Expr.alloc(self.p.allocator, E.Array, E.Array{ .items = self.args.items }, tag_expr.loc);
+
+ return Expr.alloc(
+ self.p.allocator,
+ E.Call,
+ E.Call{
+ .target = Expr{
+ .data = .{
+ .e_identifier = self.bun_identifier,
+ },
+ .loc = tag_expr.loc,
+ },
+ .can_be_unwrapped_if_unused = true,
+ .args = call_args,
+ },
+ tag_expr.loc,
+ );
+ },
+ else => Global.panic("Not implemented yet top-level jsx element: {s}", .{@tagName(tag_expr.data)}),
+ }
+ }
+
+ return Expr{ .data = .{ .e_missing = .{} }, .loc = logger.Loc.Empty };
+ }
+
+ pub fn writeRootElement(self: JSXWriter, element: E.JSXElement) Expr {
+ var tag = element.tag orelse E.Array{ .items = &.{} };
+ switch (tag.data) {
+ .e_string, .e_array => {},
+ else => {},
+ }
+ }
+
+ fn writeElementWithValidTagList(self: *JSXWriter, element: E.JSXElement, comptime valid_tags: Tag.Validator.List) bool {
+ const tag_expr = element.tag orelse return false;
+ if (tag_expr.data != .e_string) return false;
+ const str = tag_expr.data.e_string;
+ var p = self.p;
+
+ const node_type: JSNode.Tag = JSNode.Tag.names.get(str.utf8) orelse {
+ if (!str.isUTF8()) {
+ self.log.addErrorFmt(p.source, tag_expr.loc, p.allocator, "Tag \"{s}\" is invalid", .{strings.toUTF8Alloc(self.p.allocator, str.value)}) catch unreachable;
+ } else {
+ self.log.addErrorFmt(p.source, tag_expr.loc, p.allocator, "Tag \"{s}\" is invalid", .{str.utf8}) catch unreachable;
+ }
+ return false;
+ };
+
+ if (!valid_tags.get(node_type)) {
+ self.log.addErrorFmt(p.source, tag_expr.loc, p.allocator, "Tag \"{s}\" is invalid here", .{str.utf8}) catch unreachable;
+ }
+
+ return self.writeNodeType(node_type, element.properties, element.children, tag_expr.loc);
+ }
+
+ pub fn writeElement(self: *JSXWriter, element: E.JSXElement) bool {
+ const tag_expr = element.tag orelse return false;
+ if (tag_expr.data != .e_string) return false;
+ const str = tag_expr.data.e_string;
+ var p = self.p;
+
+ const node_type: JSNode.Tag = JSNode.Tag.names.get(str.utf8) orelse {
+ if (!str.isUTF8()) {
+ self.log.addErrorFmt(p.source, tag_expr.loc, p.allocator, "Tag \"{s}\" is invalid", .{strings.toUTF8Alloc(self.p.allocator, str.value)}) catch unreachable;
+ } else {
+ self.log.addErrorFmt(p.source, tag_expr.loc, p.allocator, "Tag \"{s}\" is invalid", .{str.utf8}) catch unreachable;
+ }
+ return false;
+ };
+
+ return self.writeNodeType(node_type, element.properties, element.children, tag_expr.loc);
+ }
+ };
+ }
+
pub const Writer = struct {
log: *logger.Log,
exception: JSCBase.ExceptionValueRef = null,
@@ -4510,6 +5285,25 @@ pub const Macro = struct {
errored: bool = false,
allocator: *std.mem.Allocator,
loc: logger.Loc,
+ args_value: JSC.JSValue,
+ args_i: u32 = 0,
+ args_len: u32 = 0,
+
+ pub inline fn eatArg(this: *Writer) ?JSC.JSValue {
+ if (this.args_i >= this.args_len) return null;
+ const i = this.args_i;
+ this.args_i += 1;
+ return JSC.JSObject.getIndex(this.args_value, JavaScript.VirtualMachine.vm.global, i);
+ }
+
+ pub inline fn peekArg(this: *Writer) ?JSC.JSValue {
+ if (this.args_i >= this.args_len) return null;
+ return JSC.JSObject.getIndex(this.args_value, JavaScript.VirtualMachine.vm.global, this.args_i);
+ }
+
+ pub inline fn nextJSValue(this: *Writer) ?JSC.JSValue {
+ return this.eatArg();
+ }
pub const TagOrJSNode = union(TagOrNodeType) {
tag: JSNode.Tag,
@@ -4525,13 +5319,13 @@ pub const Macro = struct {
pub fn fromJSValueRef(writer: *Writer, ctx: js.JSContextRef, value: js.JSValueRef) TagOrJSNode {
switch (js.JSValueGetType(ctx, value)) {
js.JSType.kJSTypeNumber => {
- const tag_int = @floatToInt(u8, JSC.JSValue.fromRef(first_arg).asNumber());
- if (tag_int < JSNode.min_tag or tag_int > JSNode.max_tag) {
+ const tag_int = @floatToInt(u8, JSC.JSValue.fromRef(value).asNumber());
+ if (tag_int < Tag.min_tag or tag_int > Tag.max_tag) {
throwTypeError(ctx, "Node type has invalid value", writer.exception);
writer.errored = true;
return TagOrJSNode{ .invalid = .{} };
}
- return TagOrJSNode{ .tag = @intToEnum(JSNode.Tag, tag) };
+ return TagOrJSNode{ .tag = @intToEnum(JSNode.Tag, tag_int) };
},
js.JSType.kJSTypeObject => {
if (JSCBase.GetJSPrivateData(JSNode, value)) |node| {
@@ -4546,60 +5340,166 @@ pub const Macro = struct {
},
}
}
+
+ pub fn fromJSValue(writer: *Writer, value: JSC.JSValue) TagOrJSNode {
+ return fromJSValueRef(writer, JavaScript.VirtualMachine.vm.global.ref(), value.asRef());
+ }
};
- fn writeFromJSWithTagInExpr(writer: *Writer, tag: JSNode.Tag, expr: *Expr, args: []const js.JSValueRef) ?u32 {
+ fn writeProperty(writer: *Writer, property: *G.Property) bool {
+
+ // Property is
+ // value
+ // initializer
+ // if property value is an e.spread, then key is skipped
+ // key
+
+ // value is first
+ var expect_key = true;
+ switch (TagOrJSNode.fromJSValue(writer, writer.eatArg() orelse return false)) {
+ TagOrJSNode.tag => |tag| {
+ var expr: Expr = Expr{ .loc = writer.loc, .data = .{ .e_null = E.Null{} } };
+
+ if (!writer.writeFromJSWithTagInExpr(tag, &expr)) return false;
+ property.value = switch (expr.data) {
+ .e_missing, .e_undefined => null,
+ else => expr,
+ };
+ property.flags.is_spread = expr.data == .e_spread;
+ expect_key = property.value == null or !property.flags.is_spread;
+ },
+ TagOrJSNode.node => |node| {
+ const expr = node.toExpr();
+ property.value = switch (expr.data) {
+ .e_missing, .e_undefined => null,
+ else => expr,
+ };
+ property.flags.is_spread = expr.data == .e_spread;
+ expect_key = property.value == null or !property.flags.is_spread;
+ },
+ TagOrJSNode.invalid => {
+ return false;
+ },
+ }
+
+ switch (TagOrJSNode.fromJSValue(writer, writer.eatArg() orelse return false)) {
+ TagOrJSNode.tag => |tag| {
+ var expr: Expr = Expr{ .loc = writer.loc, .data = .{ .e_null = E.Null{} } };
+
+ if (!writer.writeFromJSWithTagInExpr(tag, &expr)) return false;
+ property.initializer = switch (expr.data) {
+ .e_missing, .e_undefined => null,
+ else => expr,
+ };
+ },
+ TagOrJSNode.node => |node| {
+ const expr = node.toExpr();
+ property.initializer = switch (expr.data) {
+ .e_missing, .e_undefined => null,
+ else => expr,
+ };
+ },
+ TagOrJSNode.invalid => {
+ return false;
+ },
+ }
+
+ if (expect_key) {
+ var next_arg = writer.peekArg() orelse return false;
+ // its okay for property keys to literally be strings
+ // <property name="foo">
+ if (next_arg.isString()) {
+ var expr: Expr = Expr{ .loc = writer.loc, .data = .{ .e_string = &E.String.empty } };
+ if (!writer.writeFromJSWithTagInExpr(JSNode.Tag.e_string, &expr)) return false;
+ property.key = expr;
+ } else {
+ switch (TagOrJSNode.fromJSValue(writer, writer.eatArg() orelse return false)) {
+ TagOrJSNode.tag => |tag| {
+ var expr: Expr = Expr{ .loc = writer.loc, .data = .{ .e_null = E.Null{} } };
+ if (!writer.writeFromJSWithTagInExpr(tag, &expr)) return false;
+ property.key = expr;
+ },
+ TagOrJSNode.node => |node| {
+ property.key = node.toExpr();
+ },
+ TagOrJSNode.invalid => {
+ return false;
+ },
+ }
+ }
+ }
+
+ return true;
+ }
+
+ fn writeFromJSWithTagInExpr(writer: *Writer, tag: JSNode.Tag, expr: *Expr) bool {
switch (tag) {
- e_array => {
- var items = std.ArrayList(Expr).init(writer.allocator);
+ .e_array => {
// var e_array: E.Array = E.Array{ .items = writer.allocator.alloc(E.Array, args.len) catch return false };
- var i: u32 = 0;
- while (i < args.len) {
- switch (TagOrJSNode.fromJSValueRef(writer, writer.ctx, args[i])) {
+ const count = (writer.nextJSValue() orelse return false).toU16();
+ var i: u16 = 0;
+ var items = writer.allocator.alloc(ExprNodeIndex, count) catch return false;
+
+ while (i < items.len) : (i += 1) {
+ switch (TagOrJSNode.fromJSValue(writer, writer.eatArg() orelse return false)) {
TagOrJSNode.tag => |tag_| {
- items.ensureUnusedCapacity(1) catch return null;
- items.expandToCapacity();
+ if (!writer.writeFromJSWithTagInExpr(tag_, &items[i])) return false;
i += 1;
- i += writer.writeFromJSWithTagInExpr(tag_, &items[i], args[i..]) orelse return null;
},
TagOrJSNode.node => |node_| {
const node: JSNode = node_;
switch (node.data) {
JSNode.Tag.s_import => |import| {
- return null;
+ return false;
},
else => {
- items.append(node.toExpr()) catch return null;
- i += 1;
+ items[i] = node.toExpr();
},
}
},
TagOrJSNode.invalid => {
- return null;
+ return false;
},
}
}
- expr.* = Expr.alloc(writer.allocator, E.Array, E.Array{ .items = items.items }, writer.loc);
- return i;
+ expr.* = Expr.alloc(writer.allocator, E.Array, E.Array{ .items = items }, writer.loc);
+ return true;
+ },
+ .e_boolean => {
+ expr.* = Expr{ .loc = writer.loc, .data = .{ .e_boolean = .{
+ .value = JSC.JSValue.toBoolean(writer.nextJSValue() orelse return false),
+ } } };
+ return true;
+ },
+ .inline_true => {
+ expr.* = Expr{ .loc = writer.loc, .data = .{ .e_boolean = .{ .value = true } } };
+ return true;
},
- e_boolean => {
- expr.* = Expr{ .loc = writer.loc, .data = .{ .e_boolean = JSC.JSValue.toBoolean(JSValue.fromRef(args[0])) } };
- return 1;
+ .inline_false => {
+ expr.* = Expr{ .loc = writer.loc, .data = .{ .e_boolean = .{ .value = false } } };
+ return true;
},
- e_null => {
+ .e_null => {
expr.* = Expr{ .loc = writer.loc, .data = .{ .e_null = E.Null{} } };
- return 0;
+ return true;
},
- e_undefined => {
- expr.* = Expr{ .loc = writer.loc, .data = .{ .e_null = E.Undefined{} } };
- return 0;
+ .e_undefined => {
+ expr.* = Expr{ .loc = writer.loc, .data = .{ .e_undefined = E.Undefined{} } };
+ return true;
},
- e_number => {
- expr.* = Expr{ .loc = writer.loc, .data = .{ .e_number = JSC.JSValue.asNumber(JSValue.fromRef(args[0])) } };
- return 1;
+ .e_number => {
+ expr.* = Expr{
+ .loc = writer.loc,
+ .data = .{
+ .e_number = .{
+ .value = JSC.JSValue.asNumber(writer.nextJSValue() orelse return false),
+ },
+ },
+ };
+ return true;
},
- e_string => {
- var wtf_string = JSC.JSValue.toWTFString(JSValue.fromRef(args[0]), JavaScript.VirtualMachine.vm.global);
+ .e_string => {
+ var wtf_string = JSC.JSValue.toWTFString(writer.nextJSValue() orelse return false, JavaScript.VirtualMachine.vm.global);
if (wtf_string.isEmpty()) {
expr.* = Expr{
.loc = writer.loc,
@@ -4614,102 +5514,93 @@ pub const Macro = struct {
} else {
unreachable;
}
- return 1;
+ return true;
},
- e_reg_exp => {
- var jsstring = js.JSValueToStringCopy(writer.ctx, args[0], writer.exception);
+ .e_reg_exp => {
+ var jsstring = js.JSValueToStringCopy(writer.ctx, (writer.eatArg() orelse return false).asRef(), writer.exception);
+ defer js.JSStringRelease(jsstring);
+
const len = js.JSStringGetLength(jsstring);
- var str = try writer.allocator.alloc(u8, len + 1);
- const outlen = js.JSStringGetUTF8CString(jsstring, str, len + 1);
+ var str = writer.allocator.alloc(u8, len + 1) catch unreachable;
+ const outlen = js.JSStringGetUTF8CString(jsstring, str.ptr, len + 1);
expr.* = Expr.alloc(writer.allocator, E.RegExp, E.RegExp{ .value = str[0..outlen] }, writer.loc);
- return 1;
+ return true;
},
- e_object => {
- var i: u32 = 0;
+ .e_object => {
+ const len = (writer.nextJSValue() orelse return false).toU16();
- const len = @truncate(u16, JSC.JSValue.fromRef(args[0]).toInt32());
- },
+ var properties = writer.allocator.alloc(G.Property, len) catch return false;
+ var property_i: u16 = 0;
- e_call => {},
+ while (property_i < properties.len) : (property_i += 1) {
+ switch (TagOrJSNode.fromJSValue(writer, writer.eatArg() orelse return false)) {
+ TagOrJSNode.tag => |tag_| {
+ if (tag_ != JSNode.Tag.g_property) return false;
- e_dot => {},
- e_index => {},
- e_identifier => {},
- e_import_identifier => {},
+ if (!writer.writeProperty(
+ &properties[property_i],
+ )) return false;
+ },
+ TagOrJSNode.node => |node_| {
+ const node: JSNode = node_;
+ switch (node.data) {
+ .g_property => |property| {
+ properties[property_i] = property.*;
+ },
+ else => {
+ return false;
+ },
+ }
+ },
+ TagOrJSNode.invalid => {
+ return false;
+ },
+ }
+ }
- e_big_int => {},
- e_object => {},
- e_spread => {},
+ return true;
+ },
+ else => {
+ return false;
+ },
- e_template_part => {},
- e_template => {},
+ // .e_call => {},
- e_await => {},
- e_yield => {},
- e_if => {},
- e_import => {},
- e_this => {},
- e_class => {},
- s_import => {},
- }
- }
+ // .e_dot => {},
+ // .e_index => {},
+ // .e_identifier => {},
+ // .e_import_identifier => {},
- fn writeFromJSWithTag(writer: *Writer, tag: JSNode.Tag, node: *JSNode, args: []const js.JSValueRef) bool {
- switch (tag) {
- e_array => {
- var e_array: E.Array = E.Array{ .items = writer.allocator.alloc(E.Array, args.len) catch return false };
+ // .e_spread => {},
- var i: u32 = 0;
- while (i < args.len) : (i += 1) {}
- },
- e_boolean => {},
- e_null => {},
- e_undefined => {},
- e_call => {},
- e_dot => {},
- e_index => {},
- e_identifier => {},
- e_import_identifier => {},
- e_number => {},
- e_big_int => {},
- e_object => {},
- e_spread => {},
- e_string => {},
- e_template_part => {},
- e_template => {},
- e_reg_exp => {},
- e_await => {},
- e_yield => {},
- e_if => {},
- e_import => {},
- e_this => {},
- e_class => {},
- s_import => {},
+ // .e_template_part => {},
+ // .e_template => {},
+
+ // .e_await => {},
+ // .e_yield => {},
+ // .e_if => {},
+ // .e_import => {},
+ // .e_this => {},
+ // .e_class => {},
+ // s_import => {},
}
+
+ return false;
}
- pub fn writeFromJS(writer: *Writer, node: *JSNode, args: []const js.JSValueRef) bool {
- if (writer.errored) return false;
- const first_arg = args[0];
-
- switch (js.JSValueGetType(ctx, first_arg)) {
- js.JSType.kJSTypeNumber => {
- const value = @floatToInt(u8, JSC.JSValue.fromRef(first_arg).asNumber());
- const tag = std.meta.intToEnum(JSNode.Tag, value) catch {
- throwTypeError(ctx, "Node type has invalid value", writer.exception);
- writer.errored = true;
- return false;
- };
- if (writer.writeFromJSWithTag(writer, tag, node, args[1..])) {
- return true;
- }
+ pub fn writeFromJS(writer: *Writer) ?JSNode {
+ switch (TagOrJSNode.fromJSValueRef(writer, writer.ctx, (writer.eatArg() orelse return null).asRef())) {
+ TagOrJSNode.tag => |tag| {
+ var expr: Expr = Expr{ .loc = writer.loc, .data = .{ .e_null = E.Null{} } };
- return false;
+ if (!writer.writeFromJSWithTagInExpr(tag, &expr)) return null;
+ return JSNode.initExpr(expr);
},
- js.JSType.kJSTypeObject => {},
- else => {
- throwTypeError(writer.ctx, "Invalid Bun AST", writer.exception);
- return false;
+ TagOrJSNode.node => |node| {
+ return node;
+ },
+ TagOrJSNode.invalid => {
+ return null;
},
}
}
@@ -4728,29 +5619,59 @@ pub const Macro = struct {
JSCBase.JSError(JSCBase.getAllocator(ctx), msg, .{}, ctx, exception);
}
+ pub const BunJSXCallbackFunction = JSCBase.NewClass(
+ void,
+ .{ .name = "bunJSX" },
+ .{ .call = .{ .rfn = createFromJavaScript } },
+ .{},
+ );
+
pub fn createFromJavaScript(
- this: *JSExpr,
+ this: void,
ctx: js.JSContextRef,
function: js.JSObjectRef,
thisObject: js.JSObjectRef,
arguments: []const js.JSValueRef,
exception: js.ExceptionRef,
) js.JSObjectRef {
- if (arguments.len != 3 or !js.JSValueIsNumber(ctx, arguments[0]) or !js.JSValueIsObject(ctx, arguments[1]) or !js.JSValueIsArray(ctx, arguments[2])) {
- this.throwTypeError(ctx, "Invalid arguments for JSExpr", exception);
+ if (arguments.len != 1 or !js.JSValueIsArray(ctx, arguments[0])) {
+ throwTypeError(ctx, "bunJSX requires one array argument", exception);
return null;
}
+
+ js.JSValueProtect(ctx, arguments[0]);
+ defer Output.flush();
+ const args_value = JSC.JSValue.fromRef(arguments[0]);
+ var writer = Writer{
+ .log = JavaScript.VirtualMachine.vm.log,
+ .ctx = ctx,
+ .loc = logger.Loc.Empty,
+ .allocator = JSCBase.getAllocator(ctx),
+ .exception = exception,
+ .args_value = args_value,
+ .args_len = args_value.getLengthOfArray(JavaScript.VirtualMachine.vm.global),
+ .args_i = 0,
+ .errored = false,
+ };
+
+ if (writer.writeFromJS()) |node| {
+ var ptr = writer.allocator.create(JSNode) catch unreachable;
+ ptr.* = node;
+ return JSNode.Class.make(ctx, ptr);
+ }
+
+ return null;
}
pub fn toString(
- this: *JSExpr,
+ this: *JSNode,
ctx: js.JSContextRef,
function: js.JSObjectRef,
thisObject: js.JSObjectRef,
arguments: []const js.JSValueRef,
exception: js.ExceptionRef,
) js.JSObjectRef {
- switch (this.expr.data) {
+ switch (this.data) {
.e_string => |str| {
if (str.isBlank()) {
return JSC.ZigString.init("").toValue(JavaScript.VirtualMachine.vm.global).asRef();
@@ -4782,31 +5703,31 @@ pub const Macro = struct {
}
pub fn getTag(
- this: *JSExpr,
+ this: *JSNode,
ctx: js.JSContextRef,
thisObject: js.JSValueRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSObjectRef {
- return JSC.JSValue.jsNumberFromU16(@intCast(u16, @enumToInt(std.meta.activeTag(this.expr.data)))).asRef();
+ return JSC.JSValue.jsNumberFromU16(@intCast(u16, @enumToInt(std.meta.activeTag(this.data)))).asRef();
}
pub fn getTagName(
- this: *JSExpr,
+ this: *JSNode,
ctx: js.JSContextRef,
thisObject: js.JSValueRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSObjectRef {
- return JSC.ZigString.init(@tagName(this.expr.data)).toValue(JavaScript.VirtualMachine.vm.global).asRef();
+ return JSC.ZigString.init(@tagName(this.data)).toValue(JavaScript.VirtualMachine.vm.global).asRef();
}
pub fn getPosition(
- this: *JSExpr,
+ this: *JSNode,
ctx: js.JSContextRef,
thisObject: js.JSValueRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSObjectRef {
- return JSC.JSValue.jsNumberFromInt32(this.expr.loc.start).asRef();
+ return JSC.JSValue.jsNumberFromInt32(this.loc.start).asRef();
}
};
@@ -4863,8 +5784,8 @@ pub const Macro = struct {
}
pub const Runner = struct {
- threadlocal var args_buf: [32]js.JSObjectRef = undefined;
- threadlocal var expr_nodes_buf: [32]JSExpr = undefined;
+ threadlocal var args_buf: [2]js.JSObjectRef = undefined;
+ threadlocal var expr_nodes_buf: [1]JSNode = undefined;
threadlocal var exception_holder: Zig.ZigException.Holder = undefined;
pub fn run(
macro: Macro,
@@ -4879,20 +5800,13 @@ pub const Macro = struct {
if (comptime isDebug) Output.prettyln("<r><d>[macro]<r> call <d><b>{s}<r>", .{function_name});
exception_holder = Zig.ZigException.Holder.init();
- expr_nodes_buf[0] = JSExpr{ .expr = caller };
- args_buf[0] = JSExpr.Class.make(
+ expr_nodes_buf[0] = JSNode.initExpr(caller);
+ args_buf[0] = JSNode.Class.make(
macro.vm.global.ref(),
&expr_nodes_buf[0],
);
- for (args) |arg, i| {
- expr_nodes_buf[i + 1] = JSExpr{ .expr = arg };
- args_buf[i + 1] =
- JSExpr.Class.make(
- macro.vm.global.ref(),
- &expr_nodes_buf[i + 1],
- );
- }
- args_buf[args.len + 2] = null;
+
+ args_buf[1] = null;
var macro_callback = macro.vm.macros.get(id) orelse return caller;
var result = js.JSObjectCallAsFunctionReturnValue(macro.vm.global.ref(), macro_callback, null, args.len + 1, &args_buf);
@@ -4906,7 +5820,11 @@ pub const Macro = struct {
const value = promise.result(macro.vm.global.vm());
- return caller;
+ if (JSCBase.GetJSPrivateData(JSNode, value.asObjectRef())) |node| {
+ return node.toExpr();
+ } else {
+ return Expr{ .data = .{ .e_missing = .{} }, .loc = caller.loc };
+ }
}
};
};
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig
index 916e3e061..52c21c156 100644
--- a/src/js_parser/js_parser.zig
+++ b/src/js_parser/js_parser.zig
@@ -22,6 +22,9 @@ const JSXFactoryName = "JSX";
const JSXAutomaticName = "jsx_module";
const MacroRefs = std.AutoArrayHashMap(Ref, u32);
+const BunJSX = struct {
+ pub threadlocal var bun_jsx_identifier: E.Identifier = undefined;
+};
pub fn ExpressionTransposer(
comptime Kontext: type,
visitor: fn (ptr: *Kontext, arg: Expr, state: anytype) Expr,
@@ -88,6 +91,12 @@ pub const ImportScanner = struct {
.s_import => |st| {
var record: *ImportRecord = &p.import_records.items[st.import_record_index];
+ if (strings.eqlComptime(record.path.namespace, "macro")) {
+ record.is_unused = true;
+ record.path.is_disabled = true;
+ continue;
+ }
+
// The official TypeScript compiler always removes unused imported
// symbols. However, we deliberately deviate from the official
// TypeScript compiler's behavior doing this in a specific scenario:
@@ -1996,7 +2005,7 @@ pub const Parser = struct {
}
// Auto-import JSX
- if (p.options.jsx.parse) {
+ if (ParserType.jsx_transform_type == .react) {
const jsx_filename_symbol = p.symbols.items[p.jsx_filename.ref.inner_index];
{
@@ -2693,8 +2702,9 @@ const ImportItemForNamespaceMap = std.StringArrayHashMap(LocRef);
pub fn NewParser(
comptime js_parser_features: ParserFeatures,
) type {
+ const js_parser_jsx = if (FeatureFlags.force_macro) JSXTransformType.macro else js_parser_features.jsx;
const is_typescript_enabled = js_parser_features.typescript;
- const is_jsx_enabled = js_parser_features.jsx != .none;
+ const is_jsx_enabled = js_parser_jsx != .none;
const only_scan_imports_and_do_not_visit = js_parser_features.scan_only;
const is_react_fast_refresh_enabled = js_parser_features.react_fast_refresh;
@@ -2706,7 +2716,7 @@ pub fn NewParser(
// public only because of Binding.ToExpr
return struct {
const P = @This();
- pub const jsx_transform_type: JSXTransformType = js_parser_features.jsx;
+ pub const jsx_transform_type: JSXTransformType = js_parser_jsx;
macro_refs: MacroRefs = undefined,
allocator: *std.mem.Allocator,
options: Parser.Options,
@@ -2796,6 +2806,8 @@ pub fn NewParser(
// only applicable when is_react_fast_refresh_enabled
jsx_refresh_runtime: GeneratedSymbol = GeneratedSymbol{ .ref = Ref.None, .primary = Ref.None, .backup = Ref.None },
+ bun_jsx_ref: Ref = Ref.None,
+
// Imports (both ES6 and CommonJS) are tracked at the top level
import_records: ImportRecordList,
import_records_for_current_part: List(u32),
@@ -3627,6 +3639,8 @@ pub fn NewParser(
}
},
.macro => {
+ p.bun_jsx_ref = p.declareSymbol(.other, logger.Loc.Empty, "bunJSX") catch unreachable;
+ BunJSX.bun_jsx_identifier = E.Identifier{ .ref = p.bun_jsx_ref, .can_be_removed_if_unused = true };
p.jsx_fragment = p.declareGeneratedSymbol(.other, "Fragment") catch unreachable;
},
else => {},
@@ -10733,7 +10747,8 @@ pub fn NewParser(
});
}
- fn visitExpr(p: *P, expr: Expr) Expr {
+ // public for JSNode.JSXWriter usage
+ pub fn visitExpr(p: *P, expr: Expr) Expr {
if (only_scan_imports_and_do_not_visit) {
@compileError("only_scan_imports_and_do_not_visit must not run this.");
}
@@ -10925,52 +10940,9 @@ pub fn NewParser(
.e_jsx_element => |e_| {
switch (comptime jsx_transform_type) {
.macro => {
- const IdentifierOrNodeType = union(Tag) {
- identifier: Expr,
- expression: Expr.Tag,
- pub const Tag = enum { identifier, expression };
- };
- const tag: IdentifierOrNodeType = tagger: {
- if (e_.tag) |_tag| {
- switch (_tag.data) {
- .e_string => |str| {
- if (Expr.Tag.find(str.utf8)) |tagname| {
- break :tagger IdentifierOrNodeType{ .expression = tagname };
- }
-
- p.log.addErrorFmt(
- p.source,
- expr.loc,
- p.allocator,
- "Invalid expression tag: \"<{s}>\". Valid tags are:\n" ++ Expr.Tag.valid_names_list ++ "\n",
- .{str.utf8},
- ) catch unreachable;
- break :tagger IdentifierOrNodeType{ .identifier = p.visitExpr(_tag) };
- },
- else => {
- break :tagger IdentifierOrNodeType{ .identifier = p.visitExpr(_tag) };
- },
- }
- } else {
- break :tagger IdentifierOrNodeType{ .expression = Expr.Tag.e_array };
- }
- };
-
- for (e_.properties) |property, i| {
- if (property.kind != .spread) {
- e_.properties[i].key = p.visitExpr(e_.properties[i].key.?);
- }
-
- if (property.value != null) {
- e_.properties[i].value = p.visitExpr(e_.properties[i].value.?);
- }
-
- if (property.initializer != null) {
- e_.properties[i].initializer = p.visitExpr(e_.properties[i].initializer.?);
- }
- }
-
- return p.e(E.Missing{}, expr.loc);
+ const WriterType = js_ast.Macro.JSNode.NewJSXWriter(P);
+ var writer = WriterType.initWriter(p, &BunJSX.bun_jsx_identifier);
+ return writer.writeFunctionCall(e_.*);
},
.react => {
const tag: Expr = tagger: {
@@ -12571,7 +12543,7 @@ pub fn NewParser(
data.value.expr = p.visitExpr(expr);
// // Optionally preserve the name
- data.value.expr = p.maybeKeepExprSymbolName(expr, "default", was_anonymous_named_expr);
+ data.value.expr = p.maybeKeepExprSymbolName(data.value.expr, "default", was_anonymous_named_expr);
// Discard type-only export default statements
if (is_typescript_enabled) {
@@ -12594,7 +12566,7 @@ pub fn NewParser(
if (p.options.enable_bundling) {
var export_default_args = p.allocator.alloc(Expr, 2) catch unreachable;
export_default_args[0] = p.e(E.Identifier{ .ref = p.exports_ref }, expr.loc);
- export_default_args[1] = expr;
+ export_default_args[1] = data.value.expr;
stmts.append(p.s(S.SExpr{ .value = p.callRuntime(expr.loc, "__exportDefault", export_default_args) }, expr.loc)) catch unreachable;
return;
}
@@ -15250,7 +15222,7 @@ const JSParserMacro = NewParser(.{
.jsx = .macro,
});
const TSParserMacro = NewParser(.{
- .jsx = .react,
+ .jsx = .macro,
.typescript = true,
});
diff --git a/src/js_printer.zig b/src/js_printer.zig
index 3bdeb09ba..983444d1a 100644
--- a/src/js_printer.zig
+++ b/src/js_printer.zig
@@ -567,7 +567,7 @@ pub fn NewPrinter(
std.fmt.formatFloatScientific(float, .{}, p) catch unreachable;
}
- pub fn printQuotedUTF16(e: *Printer, text: JavascriptString, quote: u8) void {
+ pub fn printQuotedUTF16(e: *Printer, text: []const u16, quote: u8) void {
// utf-8 is a max of 4 bytes
// we leave two extra chars for "\" and "u"
var temp = [6]u8{ 0, 0, 0, 0, 0, 0 };
@@ -872,7 +872,7 @@ pub fn NewPrinter(
}
}
- pub inline fn canPrintIdentifierUTF16(p: *Printer, name: JavascriptString) bool {
+ pub inline fn canPrintIdentifierUTF16(p: *Printer, name: []const u16) bool {
// TODO: fix this
// this is commented out because something isn't quite right
// the problem may lie in isIdentifierUTF16, or it may lie in how these are allocated.
@@ -3707,7 +3707,7 @@ pub fn NewPrinter(
p.print(identifier);
}
- pub fn printIdentifierUTF16(p: *Printer, name: JavascriptString) !void {
+ pub fn printIdentifierUTF16(p: *Printer, name: []const u16) !void {
var temp = [_]u8{ 0, 0, 0, 0, 0, 0 };
const n = name.len;
var i: usize = 0;
diff --git a/src/string_immutable.zig b/src/string_immutable.zig
index 1a144a747..c9437b757 100644
--- a/src/string_immutable.zig
+++ b/src/string_immutable.zig
@@ -437,11 +437,11 @@ pub fn index(self: string, str: string) i32 {
}
}
-pub fn eqlUtf16(comptime self: string, other: JavascriptString) bool {
+pub fn eqlUtf16(comptime self: string, other: []const u16) bool {
return std.mem.eql(u16, std.unicode.utf8ToUtf16LeStringLiteral(self), other);
}
-pub fn toUTF8Alloc(allocator: *std.mem.Allocator, js: JavascriptString) !string {
+pub fn toUTF8Alloc(allocator: *std.mem.Allocator, js: []const u16) !string {
var temp: [4]u8 = undefined;
var list = std.ArrayList(u8).initCapacity(allocator, js.len) catch unreachable;
var i: usize = 0;
@@ -461,7 +461,7 @@ pub fn toUTF8Alloc(allocator: *std.mem.Allocator, js: JavascriptString) !string
}
// Check utf16 string equals utf8 string without allocating extra memory
-pub fn utf16EqlString(text: []u16, str: string) bool {
+pub fn utf16EqlString(text: []const u16, str: string) bool {
if (text.len > str.len) {
// Strings can't be equal if UTF-16 encoding is longer than UTF-8 encoding
return false;
@@ -603,7 +603,7 @@ pub fn trim(slice: anytype, values_to_strip: []const u8) @TypeOf(slice) {
return slice[begin..end];
}
-pub fn containsNonBmpCodePointUTF16(_text: JavascriptString) bool {
+pub fn containsNonBmpCodePointUTF16(_text: []const u16) bool {
const n = _text.len;
if (n > 0) {
var i: usize = 0;