Skip to content

Commit ee5f98a

Browse files
authored
React Server Components (#10043)
1 parent d19b1f6 commit ee5f98a

File tree

82 files changed

+3027
-471
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+3027
-471
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/macros/src/lib.rs

+78-62
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![deny(unused_crate_dependencies)]
22

3+
use serde::{Deserialize, Serialize};
34
use std::{
45
collections::{HashMap, HashSet},
56
sync::Arc,
@@ -44,9 +45,8 @@ pub type MacroCallback =
4445
pub struct Macros<'a> {
4546
/// Mapping of imported identifiers to import metadata.
4647
macros: HashMap<Id, MacroImport>,
47-
constants: HashMap<Id, Result<JsValue, Span>>,
48+
evaluator: Evaluator<'a>,
4849
callback: MacroCallback,
49-
source_map: &'a SourceMap,
5050
errors: &'a mut Vec<MacroError>,
5151
load_errors: HashSet<String>,
5252
assignment_span: Option<Span>,
@@ -70,10 +70,9 @@ impl<'a> Macros<'a> {
7070
) -> Self {
7171
Macros {
7272
macros: HashMap::new(),
73-
constants: HashMap::new(),
73+
evaluator: Evaluator::new(source_map),
7474
load_errors: HashSet::new(),
7575
callback,
76-
source_map,
7776
errors,
7877
assignment_span: None,
7978
in_call: false,
@@ -137,7 +136,7 @@ impl<'a> Macros<'a> {
137136
// Try to statically evaluate all of the function arguments.
138137
let mut args = Vec::with_capacity(call.args.len());
139138
for arg in &call.args {
140-
match self.eval(&*arg.expr) {
139+
match self.evaluator.eval(&*arg.expr) {
141140
Ok(val) => {
142141
if arg.spread.is_none() {
143142
args.push(val);
@@ -154,13 +153,13 @@ impl<'a> Macros<'a> {
154153
}
155154

156155
// If that was successful, call the function callback (on the JS thread).
157-
let loc = self.source_map.lookup_char_pos(call.span.lo);
156+
let loc = self.evaluator.source_map.lookup_char_pos(call.span.lo);
158157
let loc = Location {
159158
line: loc.line as u32,
160159
col: loc.col_display as u32,
161160
};
162161
match (self.callback)(src.clone(), export, args, loc) {
163-
Ok(val) => Ok(self.value_to_expr(val)?),
162+
Ok(val) => Ok(self.evaluator.value_to_expr(val)?),
164163
Err(err) => match err {
165164
MacroError::LoadError(err, _) => {
166165
self.load_errors.insert(src);
@@ -224,7 +223,7 @@ impl<'a> Fold for Macros<'a> {
224223
let imported = match &member.prop {
225224
MemberProp::Ident(id) => id.sym.to_string(),
226225
MemberProp::Computed(s) => {
227-
if let Ok(JsValue::String(s)) = self.eval(&s.expr) {
226+
if let Ok(JsValue::String(s)) = self.evaluator.eval(&s.expr) {
228227
s
229228
} else {
230229
break 'block;
@@ -263,8 +262,8 @@ impl<'a> Fold for Macros<'a> {
263262
if node.kind == VarDeclKind::Const {
264263
for decl in &node.decls {
265264
if let Some(expr) = &decl.init {
266-
let val = self.eval(&*expr);
267-
self.eval_pat(val, &decl.name);
265+
let val = self.evaluator.eval(&*expr);
266+
self.evaluator.eval_pat(val, &decl.name);
268267
}
269268
}
270269
}
@@ -286,7 +285,7 @@ impl<'a> Fold for Macros<'a> {
286285
// Error when re-assigning a property of a constant that's used in a macro.
287286
let node = node.fold_children_with(self);
288287
if let Expr::Ident(id) = &*node.obj {
289-
if let Some(constant) = self.constants.get_mut(&id.to_id()) {
288+
if let Some(constant) = self.evaluator.constants.get_mut(&id.to_id()) {
290289
if constant.is_ok() {
291290
*constant = Err(assignment_span.clone());
292291
}
@@ -299,8 +298,9 @@ impl<'a> Fold for Macros<'a> {
299298
// If the member expression evaluates to an object, continue traversing so we error in fold_ident.
300299
// Otherwise, return early to allow other properties to be accessed without error.
301300
let value = self
301+
.evaluator
302302
.eval(&*node.obj)
303-
.and_then(|obj| self.eval_member_prop(obj, &node));
303+
.and_then(|obj| self.evaluator.eval_member_prop(obj, &node));
304304
if !matches!(
305305
value,
306306
Err(..) | Ok(JsValue::Object(..) | JsValue::Array(..))
@@ -314,7 +314,7 @@ impl<'a> Fold for Macros<'a> {
314314

315315
fn fold_ident(&mut self, node: Ident) -> Ident {
316316
if self.in_call {
317-
if let Some(constant) = self.constants.get_mut(&node.to_id()) {
317+
if let Some(constant) = self.evaluator.constants.get_mut(&node.to_id()) {
318318
if matches!(constant, Ok(JsValue::Object(..) | JsValue::Array(..))) {
319319
// Mark access to constant object inside a call as an error since it could potentially be mutated.
320320
*constant = Err(node.span.clone());
@@ -362,7 +362,8 @@ fn handle_error(result: Result<Expr, MacroError>, errors: &mut Vec<MacroError>)
362362
}
363363

364364
/// A type that represents a basic JS value.
365-
#[derive(Clone, Debug)]
365+
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
366+
#[serde(untagged)]
366367
pub enum JsValue {
367368
Undefined,
368369
Null,
@@ -375,9 +376,21 @@ pub enum JsValue {
375376
Function(String),
376377
}
377378

378-
impl<'a> Macros<'a> {
379+
pub struct Evaluator<'a> {
380+
constants: HashMap<Id, Result<JsValue, Span>>,
381+
source_map: &'a SourceMap,
382+
}
383+
384+
impl<'a> Evaluator<'a> {
385+
pub fn new(source_map: &'a SourceMap) -> Evaluator<'_> {
386+
Evaluator {
387+
constants: HashMap::new(),
388+
source_map,
389+
}
390+
}
391+
379392
/// Statically evaluate a JS expression to a value, if possible.
380-
fn eval(&self, expr: &Expr) -> Result<JsValue, Span> {
393+
pub fn eval(&self, expr: &Expr) -> Result<JsValue, Span> {
381394
match expr.unwrap_parens() {
382395
Expr::Lit(lit) => match lit {
383396
Lit::Null(_) => Ok(JsValue::Null),
@@ -437,49 +450,7 @@ impl<'a> Macros<'a> {
437450
}
438451
Ok(JsValue::Array(res))
439452
}
440-
Expr::Object(obj) => {
441-
let mut res = IndexMap::with_capacity(obj.props.len());
442-
for prop in &obj.props {
443-
match prop {
444-
PropOrSpread::Prop(prop) => match &**prop {
445-
Prop::KeyValue(kv) => {
446-
let v = self.eval(&*kv.value)?;
447-
let k = match &kv.key {
448-
PropName::Ident(IdentName { sym, .. })
449-
| PropName::Str(Str { value: sym, .. }) => sym.to_string(),
450-
PropName::Num(n) => n.value.to_string(),
451-
PropName::Computed(c) => match self.eval(&*c.expr) {
452-
Err(e) => return Err(e),
453-
Ok(JsValue::String(s)) => s,
454-
Ok(JsValue::Number(n)) => n.to_string(),
455-
Ok(JsValue::Bool(b)) => b.to_string(),
456-
_ => return Err(c.span),
457-
},
458-
PropName::BigInt(v) => return Err(v.span),
459-
};
460-
461-
res.insert(k.to_string(), v);
462-
}
463-
Prop::Shorthand(s) => {
464-
if let Some(val) = self.constants.get(&s.to_id()) {
465-
res.insert(s.sym.to_string(), val.clone()?);
466-
} else {
467-
return Err(s.span);
468-
}
469-
}
470-
_ => return Err(obj.span),
471-
},
472-
PropOrSpread::Spread(spread) => {
473-
let v = self.eval(&*spread.expr)?;
474-
match v {
475-
JsValue::Object(o) => res.extend(o),
476-
_ => return Err(obj.span),
477-
}
478-
}
479-
}
480-
}
481-
Ok(JsValue::Object(res))
482-
}
453+
Expr::Object(obj) => self.eval_object(obj),
483454
Expr::Bin(bin) => match (bin.op, self.eval(&*bin.left), self.eval(&*bin.right)) {
484455
(BinaryOp::Add, Ok(JsValue::String(a)), Ok(JsValue::String(b))) => {
485456
Ok(JsValue::String(format!("{}{}", a, b)))
@@ -676,7 +647,52 @@ impl<'a> Macros<'a> {
676647
}
677648
}
678649

679-
fn eval_member_prop(&self, obj: JsValue, member: &MemberExpr) -> Result<JsValue, Span> {
650+
pub fn eval_object(&self, obj: &ObjectLit) -> Result<JsValue, Span> {
651+
let mut res = IndexMap::with_capacity(obj.props.len());
652+
for prop in &obj.props {
653+
match prop {
654+
PropOrSpread::Prop(prop) => match &**prop {
655+
Prop::KeyValue(kv) => {
656+
let v = self.eval(&*kv.value)?;
657+
let k = match &kv.key {
658+
PropName::Ident(IdentName { sym, .. }) | PropName::Str(Str { value: sym, .. }) => {
659+
sym.to_string()
660+
}
661+
PropName::Num(n) => n.value.to_string(),
662+
PropName::Computed(c) => match self.eval(&*c.expr) {
663+
Err(e) => return Err(e),
664+
Ok(JsValue::String(s)) => s,
665+
Ok(JsValue::Number(n)) => n.to_string(),
666+
Ok(JsValue::Bool(b)) => b.to_string(),
667+
_ => return Err(c.span),
668+
},
669+
PropName::BigInt(v) => return Err(v.span),
670+
};
671+
672+
res.insert(k.to_string(), v);
673+
}
674+
Prop::Shorthand(s) => {
675+
if let Some(val) = self.constants.get(&s.to_id()) {
676+
res.insert(s.sym.to_string(), val.clone()?);
677+
} else {
678+
return Err(s.span);
679+
}
680+
}
681+
_ => return Err(obj.span),
682+
},
683+
PropOrSpread::Spread(spread) => {
684+
let v = self.eval(&*spread.expr)?;
685+
match v {
686+
JsValue::Object(o) => res.extend(o),
687+
_ => return Err(obj.span),
688+
}
689+
}
690+
}
691+
}
692+
Ok(JsValue::Object(res))
693+
}
694+
695+
pub fn eval_member_prop(&self, obj: JsValue, member: &MemberExpr) -> Result<JsValue, Span> {
680696
match &member.prop {
681697
MemberProp::Ident(id) => obj.get_id(id.as_ref()).ok_or(member.span),
682698
MemberProp::Computed(prop) => {
@@ -688,7 +704,7 @@ impl<'a> Macros<'a> {
688704
}
689705

690706
/// Convert JS value to AST.
691-
fn value_to_expr(&self, value: JsValue) -> Result<Expr, MacroError> {
707+
pub fn value_to_expr(&self, value: JsValue) -> Result<Expr, MacroError> {
692708
Ok(match value {
693709
JsValue::Null => Expr::Lit(Lit::Null(Null::dummy())),
694710
JsValue::Undefined => Expr::Ident(Ident::new_no_ctxt(js_word!("undefined"), DUMMY_SP)),
@@ -764,7 +780,7 @@ impl<'a> Macros<'a> {
764780
})
765781
}
766782

767-
fn eval_pat(&mut self, value: Result<JsValue, Span>, pat: &Pat) {
783+
pub fn eval_pat(&mut self, value: Result<JsValue, Span>, pat: &Pat) {
768784
match pat {
769785
Pat::Ident(name) => {
770786
self.constants.insert(name.to_id(), value);

crates/node-bindings/src/resolver.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub struct JsFileSystemOptions {
3333
pub struct JsResolverOptions {
3434
pub fs: Option<JsFileSystemOptions>,
3535
pub include_node_modules: Option<NapiSideEffectsVariants>,
36-
pub conditions: Option<u16>,
36+
pub conditions: Option<u32>,
3737
pub module_dir_resolver: Option<JsFunction>,
3838
pub mode: u8,
3939
pub entries: Option<u8>,

0 commit comments

Comments
 (0)