Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions crates/next-core/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::future::Future;
use std::{future::Future, str::FromStr};

use anyhow::{Context, Result, bail};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
Expand Down Expand Up @@ -60,12 +60,9 @@ pub fn defines(define_env: &FxIndexMap<RcStr, Option<RcStr>>) -> CompileTimeDefi
)
.or_insert_with(|| {
if let Some(v) = v {
let val = serde_json::from_str(v);
let val = serde_json::Value::from_str(v);
match val {
Ok(serde_json::Value::Bool(v)) => CompileTimeDefineValue::Bool(v),
Ok(serde_json::Value::String(v)) => {
CompileTimeDefineValue::String(v.into())
}
Ok(v) => v.into(),
_ => CompileTimeDefineValue::Evaluate(v.clone()),
}
} else {
Expand Down
6 changes: 6 additions & 0 deletions turbopack/crates/turbo-rcstr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@ impl AsRef<[u8]> for RcStr {
}
}

impl From<RcStr> for BytesStr {
fn from(value: RcStr) -> Self {
Self::from_str_slice(value.as_str())
}
}

impl PartialEq<str> for RcStr {
fn eq(&self, other: &str) -> bool {
self.as_str() == other
Expand Down
55 changes: 54 additions & 1 deletion turbopack/crates/turbopack-ecmascript/src/analyzer/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ use std::{
sync::Arc,
};

use anyhow::{Ok, Result, bail};
use rustc_hash::{FxHashMap, FxHashSet};
use swc_core::{
atoms::Atom,
common::{GLOBALS, Mark, Span, Spanned, SyntaxContext, comments::Comments, pass::AstNodePath},
base::try_with_handler,
common::{
FileName, GLOBALS, Mark, SourceMap, Span, Spanned, SyntaxContext, comments::Comments,
pass::AstNodePath, sync::Lrc,
},
ecma::{
ast::*,
atoms::atom,
parser::{Syntax, parse_file_as_program},
utils::contains_ident_ref,
visit::{fields::*, *},
},
Expand Down Expand Up @@ -720,6 +726,53 @@ impl EvalContext {
_ => JsValue::unknown_empty(true, "unsupported expression"),
}
}

pub fn eval_single_expr_lit(expr_lit: RcStr) -> Result<JsValue> {
let cm = Lrc::new(SourceMap::default());
let fm = cm.new_source_file(FileName::Anon.into(), expr_lit.clone());

let js_value = try_with_handler(cm, Default::default(), |handler| {
GLOBALS.set(&Default::default(), || {
let program = parse_file_as_program(
&fm,
Syntax::Es(Default::default()),
EsVersion::latest(),
None,
&mut vec![],
)
.map_or_else(
|e| {
e.into_diagnostic(handler).emit();
bail!(r#"Failed to evaluate compile-time defined value expression: "{expr_lit}""#)
},
Ok,
)?;

let eval_context = EvalContext::new(
&program,
Mark::new(),Mark::new(),
Default::default(),
None,
None,
);

if let Program::Script(script) = program {
if script.body.len() == 1
&& let Some(Stmt::Expr(expr_stmt)) = script.body.first()
{
Ok(eval_context.eval(&expr_stmt.expr))
} else {
bail!(r#"Failed to parse compile-time defined value expression: "{expr_lit}""#)
}
} else {
bail!(r#"Failed to parse compile-time defined value: "{expr_lit}" in non-script context"#)
}
})
})
.map_err(|e| e.to_pretty_error())?;

Ok(js_value)
}
}

enum EarlyReturn {
Expand Down
83 changes: 48 additions & 35 deletions turbopack/crates/turbopack-ecmascript/src/analyzer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ use turbopack_core::compile_time_info::{

use self::imports::ImportAnnotations;
pub(crate) use self::imports::ImportMap;
use crate::{references::require_context::RequireContextMap, utils::StringifyJs};
use crate::{
analyzer::graph::EvalContext, references::require_context::RequireContextMap,
utils::StringifyJs,
};

pub mod builtin;
pub mod graph;
Expand Down Expand Up @@ -594,63 +597,73 @@ impl From<ConstantValue> for JsValue {
}
}

impl From<&CompileTimeDefineValue> for JsValue {
fn from(v: &CompileTimeDefineValue) -> Self {
match v {
CompileTimeDefineValue::Null => JsValue::Constant(ConstantValue::Null),
CompileTimeDefineValue::Bool(b) => JsValue::Constant((*b).into()),
CompileTimeDefineValue::Number(n) => JsValue::Constant(ConstantValue::Num(
ConstantNumber(n.as_str().parse::<f64>().unwrap()),
)),
CompileTimeDefineValue::String(s) => JsValue::Constant(s.as_str().into()),
impl TryFrom<&CompileTimeDefineValue> for JsValue {
type Error = anyhow::Error;

fn try_from(value: &CompileTimeDefineValue) -> Result<Self> {
match value {
CompileTimeDefineValue::Null => Ok(JsValue::Constant(ConstantValue::Null)),
CompileTimeDefineValue::Bool(b) => Ok(JsValue::Constant((*b).into())),
CompileTimeDefineValue::Number(n) => Ok(JsValue::Constant(ConstantValue::Num(
ConstantNumber(n.as_str().parse::<f64>()?),
))),
CompileTimeDefineValue::String(s) => Ok(JsValue::Constant(s.as_str().into())),
CompileTimeDefineValue::Array(a) => {
let mut js_value = JsValue::Array {
total_nodes: a.len() as u32,
items: a.iter().map(|i| i.into()).collect(),
items: a.iter().map(|i| i.try_into()).try_collect()?,
mutable: false,
};
js_value.update_total_nodes();
js_value
Ok(js_value)
}
CompileTimeDefineValue::Object(m) => {
let mut js_value = JsValue::Object {
total_nodes: m.len() as u32,
parts: m
.iter()
.map(|(k, v)| ObjectPart::KeyValue(k.clone().into(), v.into()))
.collect(),
.map(|(k, v)| {
Ok::<ObjectPart, anyhow::Error>(ObjectPart::KeyValue(
k.clone().into(),
v.try_into()?,
))
})
.try_collect()?,
mutable: false,
};
js_value.update_total_nodes();
js_value
}
CompileTimeDefineValue::Undefined => JsValue::Constant(ConstantValue::Undefined),
CompileTimeDefineValue::Evaluate(s) => {
JsValue::Constant(ConstantValue::Evaluate(s.clone()))
Ok(js_value)
}
CompileTimeDefineValue::Undefined => Ok(JsValue::Constant(ConstantValue::Undefined)),
CompileTimeDefineValue::Evaluate(s) => EvalContext::eval_single_expr_lit(s.clone()),
}
}
}

impl From<&FreeVarReference> for JsValue {
fn from(v: &FreeVarReference) -> Self {
match v {
FreeVarReference::Value(v) => v.into(),
impl TryFrom<&FreeVarReference> for JsValue {
type Error = anyhow::Error;

fn try_from(value: &FreeVarReference) -> Result<Self> {
match value {
FreeVarReference::Value(v) => v.try_into(),
FreeVarReference::Ident(_) => {
JsValue::unknown_empty(false, "compile time injected ident")
}
FreeVarReference::Member(_, _) => {
JsValue::unknown_empty(false, "compile time injected member")
}
FreeVarReference::EcmaScriptModule { .. } => {
JsValue::unknown_empty(false, "compile time injected free var module")
}
FreeVarReference::Error(_) => {
JsValue::unknown_empty(false, "compile time injected free var error")
Ok(JsValue::unknown_empty(false, "compile time injected ident"))
}
FreeVarReference::Member(_, _) => Ok(JsValue::unknown_empty(
false,
"compile time injected member",
)),
FreeVarReference::EcmaScriptModule { .. } => Ok(JsValue::unknown_empty(
false,
"compile time injected free var module",
)),
FreeVarReference::Error(_) => Ok(JsValue::unknown_empty(
false,
"compile time injected free var error",
)),
FreeVarReference::InputRelative(kind) => {
use turbopack_core::compile_time_info::InputRelativeConstant;
JsValue::unknown_empty(
Ok(JsValue::unknown_empty(
false,
match kind {
InputRelativeConstant::DirName => {
Expand All @@ -660,7 +673,7 @@ impl From<&FreeVarReference> for JsValue {
"compile time injected free var referencing the file name"
}
},
)
))
}
}
}
Expand Down
1 change: 1 addition & 0 deletions turbopack/crates/turbopack-ecmascript/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#![feature(int_roundings)]
#![feature(arbitrary_self_types)]
#![feature(arbitrary_self_types_pointers)]
#![feature(iterator_try_collect)]
#![recursion_limit = "256"]

pub mod analyzer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use std::{path::PathBuf, str::FromStr};

Check warning on line 1 in turbopack/crates/turbopack-ecmascript/src/references/constant_value.rs

View workflow job for this annotation

GitHub Actions / Benchmark Rust Crates (tiny)

unused imports: `path::PathBuf` and `str::FromStr`

use anyhow::Result;
use serde::{Deserialize, Serialize};
use swc_core::{
common::{DUMMY_SP, SourceMap, sync::Lrc},
common::{DUMMY_SP, FileName, SourceMap, sync::Lrc},
ecma::{
ast::{ArrayLit, EsVersion, Expr, KeyValueProp, ObjectLit, Prop, PropName, Str},
parser::{Syntax, parse_file_as_expr},
},
quote,
};
use turbo_rcstr::RcStr;
use turbo_tasks::{NonLocalValue, TaskInput, Vc, debug::ValueDebugFormat, trace::TraceRawVcs};
use turbopack_core::{chunk::ChunkingContext, compile_time_info::CompileTimeDefineValue};

Expand Down Expand Up @@ -105,20 +106,13 @@
CompileTimeDefineValue::Undefined => {
quote!("(\"TURBOPACK compile-time value\", void 0)" as Expr)
}
CompileTimeDefineValue::Evaluate(ref s) => parse_code_to_expr(s.to_string()),
CompileTimeDefineValue::Evaluate(ref s) => parse_single_expr_lit(s.clone()),
}
}

fn parse_code_to_expr(code: String) -> Expr {
fn parse_single_expr_lit(expr_lit: RcStr) -> Expr {
let cm = Lrc::new(SourceMap::default());
let fm = cm.new_source_file(
Lrc::new(
PathBuf::from_str("__compile_time_define_value_internal__.js")
.unwrap()
.into(),
),
code.clone(),
);
let fm = cm.new_source_file(FileName::Anon.into(), expr_lit.clone());
parse_file_as_expr(
&fm,
Syntax::Es(Default::default()),
Expand All @@ -127,7 +121,7 @@
&mut vec![],
)
.map_or(
quote!("$s" as Expr, s: Expr = code.into()),
quote!("(\"Failed parsed TURBOPACK compile-time value\", $s)" as Expr, s: Expr = expr_lit.as_str().into()),
|expr| quote!("(\"TURBOPACK compile-time value\", $e)" as Expr, e: Expr = *expr),
)
}
4 changes: 2 additions & 2 deletions turbopack/crates/turbopack-ecmascript/src/references/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2909,11 +2909,11 @@ async fn value_visitor_inner(
&DefinableNameSegment::TypeOf,
)
{
return Ok(((&*value.await?).into(), true));
return Ok(((&*value.await?).try_into()?, true));
}

if let Some(value) = v.match_define(&*compile_time_info.defines.individual().await?) {
return Ok(((&*value.await?).into(), true));
return Ok(((&*value.await?).try_into()?, true));
}
}
let value = match v {
Expand Down
6 changes: 3 additions & 3 deletions turbopack/crates/turbopack-tests/tests/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use turbopack_core::{
EvaluatableAssets, MinifyType, availability_info::AvailabilityInfo,
},
compile_time_defines,
compile_time_info::{CompileTimeDefineValue, CompileTimeInfo, DefineableNameSegment},
compile_time_info::{CompileTimeDefineValue, CompileTimeInfo, DefinableNameSegment},
condition::ContextCondition,
context::AssetContext,
environment::{BrowserEnvironment, Environment, ExecutionEnvironment, NodeJsEnvironment},
Expand Down Expand Up @@ -271,12 +271,12 @@ async fn run_test_operation(resource: RcStr) -> Result<Vc<FileSystemPath>> {
);

defines.0.insert(
vec![DefineableNameSegment::from("DEFINED_EVALED")],
vec![DefinableNameSegment::from("DEFINED_EVALUATE")],
CompileTimeDefineValue::Evaluate("1 + 1".into()),
);

defines.0.insert(
vec![DefineableNameSegment::from("DEFINED_EVALED_NESTED")],
vec![DefinableNameSegment::from("DEFINED_EVALUATE_NESTED")],
CompileTimeDefineValue::Array(vec![
CompileTimeDefineValue::Bool(true),
CompileTimeDefineValue::Undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ if (DEFINED_ARRAY) {
console.log('DEFINED_ARRAY', DEFINED_ARRAY)
}

if (DEFINED_EVALED) {
console.log('DEFINED_EVALED', DEFINED_EVALED)
if (DEFINED_EVALUATE) {
console.log('DEFINED_EVALUATE', DEFINED_EVALUATE)
}

if (DEFINED_EVALED_NESTED) {
console.log('DEFINED_EVALED_NESTED', DEFINED_EVALED_NESTED)
if (DEFINED_EVALUATE_NESTED) {
console.log('DEFINED_EVALUATE_NESTED', DEFINED_EVALUATE_NESTED)
}

if (A.VERY.LONG.DEFINED.VALUE) {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading