Skip to content

Commit 339d1f8

Browse files
authored
feat: Combine config enums (#11)
* feat: Combine config enums * Simplify test module matching * reorder `InstrumentationConfig::new` args
1 parent 011b38e commit 339d1f8

File tree

17 files changed

+281
-296
lines changed

17 files changed

+281
-296
lines changed

src/config.rs

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,60 @@
33
* This product includes software developed at Datadog (<https://www.datadoghq.com>/). Copyright 2025 Datadog, Inc.
44
**/
55
use crate::function_query::FunctionQuery;
6-
use nodejs_semver::{Range, Version};
6+
use nodejs_semver::{Range, SemverError, Version};
77
use std::path::PathBuf;
88

9-
#[derive(Clone, Debug)]
10-
pub enum InstrumentationOperator {
11-
Callback,
12-
Promise,
13-
Sync,
14-
Async,
9+
#[derive(Debug, Clone)]
10+
pub struct ModuleMatcher {
11+
pub name: String,
12+
pub version_range: Range,
13+
pub file_path: PathBuf,
1514
}
1615

17-
impl InstrumentationOperator {
16+
impl ModuleMatcher {
17+
/// Creates a new `ModuleMatcher` instance.
18+
/// # Errors
19+
/// Returns an error if the version range cannot be parsed.
20+
pub fn new(name: &str, version_range: &str, file_path: &str) -> Result<Self, SemverError> {
21+
Ok(Self {
22+
name: name.to_string(),
23+
version_range: Range::parse(version_range)?,
24+
file_path: PathBuf::from(file_path),
25+
})
26+
}
27+
1828
#[must_use]
19-
pub fn as_str(&self) -> &'static str {
20-
match self {
21-
InstrumentationOperator::Callback => "traceCallback",
22-
InstrumentationOperator::Promise => "tracePromise",
23-
InstrumentationOperator::Sync => "traceSync",
24-
InstrumentationOperator::Async => "traceAsync",
25-
}
29+
pub fn matches(&self, module_name: &str, version: &str, file_path: &PathBuf) -> bool {
30+
let version: Version = match version.parse() {
31+
Ok(v) => v,
32+
Err(e) => {
33+
println!("Failed to parse version {version}: {e}");
34+
return false;
35+
}
36+
};
37+
38+
self.name == module_name
39+
&& version.satisfies(&self.version_range)
40+
&& self.file_path == *file_path
2641
}
2742
}
2843

2944
#[derive(Debug, Clone)]
3045
pub struct InstrumentationConfig {
31-
pub module_name: String,
32-
pub version_range: Range,
33-
pub file_path: PathBuf,
34-
pub function_query: FunctionQuery,
35-
pub operator: InstrumentationOperator,
3646
pub channel_name: String,
47+
pub module: ModuleMatcher,
48+
pub function_query: FunctionQuery,
49+
}
50+
51+
impl InstrumentationConfig {
52+
#[must_use]
53+
pub fn new(channel_name: &str, module: ModuleMatcher, function_query: FunctionQuery) -> Self {
54+
Self {
55+
channel_name: channel_name.to_string(),
56+
module,
57+
function_query,
58+
}
59+
}
3760
}
3861

3962
#[derive(Debug, Clone)]
@@ -44,35 +67,22 @@ pub struct Config {
4467

4568
impl Config {
4669
#[must_use]
47-
pub fn new(instrumentations: Vec<InstrumentationConfig>, dc_module: String) -> Self {
70+
pub fn new(instrumentations: Vec<InstrumentationConfig>, dc_module: Option<String>) -> Self {
4871
Self {
4972
instrumentations,
50-
dc_module,
73+
dc_module: dc_module.unwrap_or_else(|| "diagnostics_channel".to_string()),
5174
}
5275
}
5376

5477
#[must_use]
55-
pub fn new_single_with_default_dc_module(instrumentation: InstrumentationConfig) -> Self {
56-
Self {
57-
instrumentations: vec![instrumentation],
58-
dc_module: "diagnostics_channel".to_string(),
59-
}
78+
pub fn new_single(instrumentation: InstrumentationConfig) -> Self {
79+
Self::new(vec![instrumentation], None)
6080
}
6181
}
6282

6383
impl InstrumentationConfig {
6484
#[must_use]
6585
pub fn matches(&self, module_name: &str, version: &str, file_path: &PathBuf) -> bool {
66-
let version: Version = match version.parse() {
67-
Ok(v) => v,
68-
Err(e) => {
69-
println!("Failed to parse version {version}: {e}");
70-
return false;
71-
}
72-
};
73-
74-
self.module_name == module_name
75-
&& version.satisfies(&self.version_range)
76-
&& self.file_path == *file_path
86+
self.module.matches(module_name, version, file_path)
7787
}
7888
}

src/function_query.rs

Lines changed: 143 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use swc_core::ecma::ast::{FnDecl, FnExpr, Function};
66

77
#[derive(Debug, Clone)]
8-
pub enum FunctionType {
8+
pub(crate) enum FunctionType {
99
FunctionDeclaration,
1010
FunctionExpression,
1111
Method,
@@ -15,45 +15,161 @@ pub enum FunctionType {
1515
pub enum FunctionKind {
1616
Sync,
1717
Async,
18-
Generator,
19-
AsyncGenerator,
2018
}
2119

2220
impl FunctionKind {
2321
#[must_use]
2422
pub fn is_async(&self) -> bool {
25-
matches!(self, FunctionKind::Async | FunctionKind::AsyncGenerator)
26-
}
27-
28-
#[must_use]
29-
pub fn is_generator(&self) -> bool {
30-
matches!(self, FunctionKind::Generator | FunctionKind::AsyncGenerator)
23+
matches!(self, FunctionKind::Async)
3124
}
3225

3326
#[must_use]
3427
pub fn matches(&self, func: &Function) -> bool {
3528
match self {
3629
FunctionKind::Sync => !func.is_async && !func.is_generator,
3730
FunctionKind::Async => func.is_async && !func.is_generator,
38-
FunctionKind::Generator => !func.is_async && func.is_generator,
39-
FunctionKind::AsyncGenerator => func.is_async && func.is_generator,
31+
}
32+
}
33+
34+
#[must_use]
35+
pub fn tracing_operator(&self) -> &'static str {
36+
match self {
37+
FunctionKind::Sync => "traceSync",
38+
FunctionKind::Async => "tracePromise",
4039
}
4140
}
4241
}
4342

4443
#[derive(Debug, Clone)]
45-
pub struct FunctionQuery {
46-
pub name: String,
47-
pub class: Option<String>,
48-
pub typ: FunctionType,
49-
pub kind: FunctionKind,
50-
pub index: usize,
44+
pub enum FunctionQuery {
45+
ClassConstructor {
46+
class_name: String,
47+
index: usize,
48+
},
49+
ClassMethod {
50+
class_name: String,
51+
method_name: String,
52+
kind: FunctionKind,
53+
index: usize,
54+
},
55+
ObjectMethod {
56+
method_name: String,
57+
kind: FunctionKind,
58+
index: usize,
59+
},
60+
FunctionDeclaration {
61+
function_name: String,
62+
kind: FunctionKind,
63+
index: usize,
64+
},
65+
FunctionExpression {
66+
expression_name: String,
67+
kind: FunctionKind,
68+
index: usize,
69+
},
5170
}
5271

5372
impl FunctionQuery {
73+
#[must_use]
74+
pub fn class_constructor(class_name: &str) -> Self {
75+
FunctionQuery::ClassConstructor {
76+
class_name: class_name.to_string(),
77+
index: 0,
78+
}
79+
}
80+
81+
#[must_use]
82+
pub fn class_method(class_name: &str, method_name: &str, kind: FunctionKind) -> Self {
83+
FunctionQuery::ClassMethod {
84+
class_name: class_name.to_string(),
85+
method_name: method_name.to_string(),
86+
kind,
87+
index: 0,
88+
}
89+
}
90+
91+
#[must_use]
92+
pub fn object_method(method_name: &str, kind: FunctionKind) -> Self {
93+
FunctionQuery::ObjectMethod {
94+
method_name: method_name.to_string(),
95+
kind,
96+
index: 0,
97+
}
98+
}
99+
100+
#[must_use]
101+
pub fn function_declaration(function_name: &str, kind: FunctionKind) -> Self {
102+
FunctionQuery::FunctionDeclaration {
103+
function_name: function_name.to_string(),
104+
kind,
105+
index: 0,
106+
}
107+
}
108+
109+
#[must_use]
110+
pub fn function_expression(expression_name: &str, kind: FunctionKind) -> Self {
111+
FunctionQuery::FunctionExpression {
112+
expression_name: expression_name.to_string(),
113+
kind,
114+
index: 0,
115+
}
116+
}
117+
118+
pub(crate) fn kind(&self) -> &FunctionKind {
119+
match self {
120+
FunctionQuery::ClassConstructor { .. } => &FunctionKind::Sync,
121+
FunctionQuery::ClassMethod { kind, .. }
122+
| FunctionQuery::ObjectMethod { kind, .. }
123+
| FunctionQuery::FunctionDeclaration { kind, .. }
124+
| FunctionQuery::FunctionExpression { kind, .. } => kind,
125+
}
126+
}
127+
128+
pub(crate) fn name(&self) -> &str {
129+
match self {
130+
FunctionQuery::ClassConstructor { .. } => "constructor",
131+
FunctionQuery::ClassMethod { method_name, .. }
132+
| FunctionQuery::ObjectMethod { method_name, .. } => method_name,
133+
FunctionQuery::FunctionDeclaration { function_name, .. } => function_name,
134+
FunctionQuery::FunctionExpression {
135+
expression_name, ..
136+
} => expression_name,
137+
}
138+
}
139+
140+
pub(crate) fn typ(&self) -> FunctionType {
141+
match self {
142+
FunctionQuery::ClassConstructor { .. }
143+
| FunctionQuery::ClassMethod { .. }
144+
| FunctionQuery::ObjectMethod { .. } => FunctionType::Method,
145+
FunctionQuery::FunctionDeclaration { .. } => FunctionType::FunctionDeclaration,
146+
FunctionQuery::FunctionExpression { .. } => FunctionType::FunctionExpression,
147+
}
148+
}
149+
150+
#[must_use]
151+
pub(crate) fn index(&self) -> usize {
152+
match self {
153+
FunctionQuery::ClassConstructor { index, .. }
154+
| FunctionQuery::ClassMethod { index, .. }
155+
| FunctionQuery::ObjectMethod { index, .. }
156+
| FunctionQuery::FunctionDeclaration { index, .. }
157+
| FunctionQuery::FunctionExpression { index, .. } => *index,
158+
}
159+
}
160+
161+
#[must_use]
162+
pub(crate) fn class_name(&self) -> Option<&str> {
163+
match self {
164+
FunctionQuery::ClassConstructor { class_name, .. }
165+
| FunctionQuery::ClassMethod { class_name, .. } => Some(class_name),
166+
_ => None,
167+
}
168+
}
169+
54170
fn maybe_increment_count(&self, matches_except_count: bool, count: &mut usize) -> bool {
55171
if matches_except_count {
56-
if self.index == *count {
172+
if self.index() == *count {
57173
true
58174
} else {
59175
*count += 1;
@@ -65,23 +181,23 @@ impl FunctionQuery {
65181
}
66182

67183
pub fn matches_decl(&self, func: &FnDecl, count: &mut usize) -> bool {
68-
let matches_except_count = matches!(self.typ, FunctionType::FunctionDeclaration)
69-
&& self.kind.matches(&func.function)
70-
&& func.ident.sym == self.name;
184+
let matches_except_count = matches!(self.typ(), FunctionType::FunctionDeclaration)
185+
&& self.kind().matches(&func.function)
186+
&& func.ident.sym == self.name();
71187
self.maybe_increment_count(matches_except_count, count)
72188
}
73189

74190
pub fn matches_expr(&self, func: &FnExpr, count: &mut usize, name: &str) -> bool {
75-
let matches_except_count = matches!(self.typ, FunctionType::FunctionExpression)
76-
&& self.kind.matches(&func.function)
77-
&& name == self.name;
191+
let matches_except_count = matches!(self.typ(), FunctionType::FunctionExpression)
192+
&& self.kind().matches(&func.function)
193+
&& name == self.name();
78194
self.maybe_increment_count(matches_except_count, count)
79195
}
80196

81197
pub fn matches_method(&self, func: &Function, count: &mut usize, name: &str) -> bool {
82-
let matches_except_count = matches!(self.typ, FunctionType::Method)
83-
&& self.kind.matches(func)
84-
&& name == self.name;
198+
let matches_except_count = matches!(self.typ(), FunctionType::Method)
199+
&& self.kind().matches(func)
200+
&& name == self.name();
85201
self.maybe_increment_count(matches_except_count, count)
86202
}
87203
}

src/instrumentation.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ impl Instrumentation {
5353
ArrowExpr {
5454
params: vec![],
5555
body: Box::new(body.into()),
56-
is_async: self.config.function_query.kind.is_async(),
57-
is_generator: self.config.function_query.kind.is_generator(),
56+
is_async: self.config.function_query.kind().is_async(),
57+
is_generator: false,
5858
type_params: None,
5959
return_type: None,
6060
span: Span::default(),
@@ -68,7 +68,7 @@ impl Instrumentation {
6868
span: Span::default(),
6969
value: format!(
7070
"orchestrion:{}:{}",
71-
self.config.module_name, self.config.channel_name
71+
self.config.module.name, self.config.channel_name
7272
)
7373
.into(),
7474
raw: None,
@@ -99,7 +99,7 @@ impl Instrumentation {
9999
let trace_ident = ident!(format!(
100100
"tr_ch_apm${}.{}",
101101
&self.config.channel_name,
102-
self.config.operator.as_str()
102+
self.config.function_query.kind().tracing_operator()
103103
));
104104

105105
body.stmts = vec![
@@ -230,8 +230,7 @@ impl Instrumentation {
230230
self.is_correct_class = self
231231
.config
232232
.function_query
233-
.class
234-
.as_ref()
233+
.class_name()
235234
.is_none_or(|class| node.ident.sym.as_ref() == class);
236235
true
237236
}
@@ -261,11 +260,11 @@ impl Instrumentation {
261260
}
262261

263262
pub fn visit_mut_constructor(&mut self, node: &mut Constructor) -> bool {
264-
if !self.is_correct_class || self.config.function_query.name != "constructor" {
263+
if !self.is_correct_class || self.config.function_query.name() != "constructor" {
265264
return false;
266265
}
267266

268-
if self.count == self.config.function_query.index && node.body.is_some() {
267+
if self.count == self.config.function_query.index() && node.body.is_some() {
269268
if let Some(body) = node.body.as_mut() {
270269
self.insert_constructor_tracing(body);
271270
}

0 commit comments

Comments
 (0)