Skip to content

Commit aaa8d19

Browse files
committed
Emit build error when 'use cache' directive is misspelled
Handles cases like: - `'use cache:remote'` (missing space after colon) - `'use cache : default'` (extra space before colon) - `'use cache private'` (missing colon) - `'use cache: '` (missing cache kind) closes NAR-392
1 parent 370ba8d commit aaa8d19

File tree

4 files changed

+125
-13
lines changed

4 files changed

+125
-13
lines changed

crates/next-custom-transforms/src/transforms/server_actions.rs

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2739,7 +2739,7 @@ impl DirectiveVisitor<'_> {
27392739
});
27402740
} else
27412741
// `use cache` or `use cache: foo`
2742-
if value == "use cache" || value.starts_with("use cache: ") {
2742+
if let Some(rest) = value.strip_prefix("use cache") {
27432743
// Increment telemetry counter tracking usage of "use cache" directives
27442744

27452745
if in_fn_body && !allow_inline {
@@ -2759,25 +2759,59 @@ impl DirectiveVisitor<'_> {
27592759
});
27602760
}
27612761

2762-
if value == "use cache" {
2762+
if rest.is_empty() {
27632763
self.directive = Some(Directive::UseCache {
27642764
cache_kind: rcstr!("default"),
27652765
});
2766+
27662767
self.increment_cache_usage_counter("default");
2768+
2769+
return true;
2770+
}
2771+
2772+
if rest.starts_with(": ") {
2773+
let cache_kind = RcStr::from(rest.split_at(": ".len()).1);
2774+
2775+
if !cache_kind.is_empty() {
2776+
if !self.config.cache_kinds.contains(&cache_kind) {
2777+
emit_error(ServerActionsErrorKind::UnknownCacheKind {
2778+
span: *span,
2779+
cache_kind: cache_kind.clone(),
2780+
});
2781+
}
2782+
2783+
self.increment_cache_usage_counter(&cache_kind);
2784+
self.directive = Some(Directive::UseCache { cache_kind });
2785+
2786+
return true;
2787+
}
2788+
}
2789+
2790+
// Emit helpful errors for variants like "use cache:<cache-kind>",
2791+
// "use cache : <cache-kind>", and "use cache <cache-kind>" etc.
2792+
let expected_directive = if let Some(colon_pos) = rest.find(':') {
2793+
let kind = rest[colon_pos + 1..].trim();
2794+
2795+
if kind.is_empty() {
2796+
"use cache: <cache-kind>".to_string()
2797+
} else {
2798+
format!("use cache: {kind}")
2799+
}
27672800
} else {
2768-
// Slice the value after "use cache: "
2769-
let cache_kind = RcStr::from(value.split_at("use cache: ".len()).1);
2770-
2771-
if !self.config.cache_kinds.contains(&cache_kind) {
2772-
emit_error(ServerActionsErrorKind::UnknownCacheKind {
2773-
span: *span,
2774-
cache_kind: cache_kind.clone(),
2775-
});
2801+
let kind = rest.trim();
2802+
2803+
if kind.is_empty() {
2804+
"use cache".to_string()
2805+
} else {
2806+
format!("use cache: {kind}")
27762807
}
2808+
};
27772809

2778-
self.increment_cache_usage_counter(&cache_kind);
2779-
self.directive = Some(Directive::UseCache { cache_kind });
2780-
}
2810+
emit_error(ServerActionsErrorKind::MisspelledDirective {
2811+
span: *span,
2812+
directive: value.to_string(),
2813+
expected_directive,
2814+
});
27812815

27822816
return true;
27832817
} else {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use cache:remote'
2+
3+
export async function foo() {
4+
return 'data'
5+
}
6+
7+
export async function bar() {
8+
'use cache : default'
9+
return 'data'
10+
}
11+
12+
export async function baz() {
13+
'use cache private'
14+
return 'data'
15+
}
16+
17+
export async function qux() {
18+
'use cache '
19+
return 'data'
20+
}
21+
22+
export async function quux() {
23+
'use cache: '
24+
return 'data'
25+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export async function foo() {
2+
return 'data';
3+
}
4+
export async function bar() {
5+
return 'data';
6+
}
7+
export async function baz() {
8+
return 'data';
9+
}
10+
export async function qux() {
11+
return 'data';
12+
}
13+
export async function quux() {
14+
return 'data';
15+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
x Did you mean "use cache: remote"? "use cache:remote" is not a supported directive name."
2+
|
3+
,-[input.js:1:1]
4+
1 | 'use cache:remote'
5+
: ^^^^^^^^^^^^^^^^^^
6+
`----
7+
x Did you mean "use cache: default"? "use cache : default" is not a supported directive name."
8+
|
9+
,-[input.js:8:1]
10+
7 | export async function bar() {
11+
8 | 'use cache : default'
12+
: ^^^^^^^^^^^^^^^^^^^^^
13+
9 | return 'data'
14+
`----
15+
x Did you mean "use cache: private"? "use cache private" is not a supported directive name."
16+
|
17+
,-[input.js:13:1]
18+
12 | export async function baz() {
19+
13 | 'use cache private'
20+
: ^^^^^^^^^^^^^^^^^^^
21+
14 | return 'data'
22+
`----
23+
x Did you mean "use cache"? "use cache " is not a supported directive name."
24+
|
25+
,-[input.js:18:1]
26+
17 | export async function qux() {
27+
18 | 'use cache '
28+
: ^^^^^^^^^^^^
29+
19 | return 'data'
30+
`----
31+
x Did you mean "use cache: <cache-kind>"? "use cache: " is not a supported directive name."
32+
|
33+
,-[input.js:23:1]
34+
22 | export async function quux() {
35+
23 | 'use cache: '
36+
: ^^^^^^^^^^^^^
37+
24 | return 'data'
38+
`----

0 commit comments

Comments
 (0)