Repository: gleam-lang/gleam (rust)

Issue:
Small inconsistency in target strings
In Gleam v1.6.0-rc-1, the following code is valid and compiles:
```gleam
@target(js)
fn wibble() {
  todo
}
```
But this doesn't:
```gleam
@external(js, "./wibble.mjs", "wobble")
fn wibble() -> Nil
```

The shorthands, `js` and `erl` are allowed in various places such as `@target` and the `--target` flag for `gleam build` and `gleam run`. However, they are not allowed in `@external`. Small point, but I would expect the same set of values to be accepted in all such places.

Pull request description:
Deprecate shorthand target names
Closes #3826

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0fd8627ba..7e1b13622 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,6 +27,10 @@
   expression.
   ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
 
+- The shorthand names for the two targets, `erl` and `js` are now
+  deprecated in code such as `@target`.
+  ([Surya Rose](https://github.com/GearsDatapacks))
+
 ### Build tool
 
 - Improved the error message you get when trying to add a package that doesn't
diff --git a/README.md b/README.md
index b1ceab29c..6f264bc04 100644
--- a/README.md
+++ b/README.md
@@ -60,6 +60,7 @@ Thank you to our sponsors! Gleam would not be possible without you.
   <a href="https://github.com/requestben">Ben Martin</a> -
   <a href="https://github.com/bgmarx">Ben Marx</a> -
   <a href="https://github.com/benmyles">Ben Myles</a> -
+  <a href="https://github.com/bbkane">Benjamin Kane</a> -
   <a href="https://github.com/bcpeinhardt">Benjamin Peinhardt</a> -
   <a href="https://github.com/bentomas">Benjamin Thomas</a> -
   <a href="https://github.com/berkanteber">Berkan Teber</a> -
@@ -153,6 +154,7 @@ Thank you to our sponsors! Gleam would not be possible without you.
   <a href="https://github.com/ggobbe">ggobbe</a> -
   <a href="https://github.com/giacomocavalieri">Giacomo Cavalieri</a> -
   <a href="https://github.com/giovannibonetti">Giovanni Kock Bonetti</a> -
+  <a href="https://github.com/glippert">glippert</a> -
   <a href="https://github.com/obmarg">Graeme Coupar</a> -
   <a href="https://github.com/grottohub">grotto</a> -
   <a href="https://github.com/nirev">Guilherme de Maio</a> -
@@ -193,7 +195,6 @@ Thank you to our sponsors! Gleam would not be possible without you.
   <a href="https://github.com/monzool">Jan Skriver Sørensen</a> -
   <a href="https://github.com/jlgeering">Jean-Luc Geering</a> -
   <a href="https://github.com/okkdev">Jen Stehlik</a> -
-  <a href="https://github.com/dukeofcool199">Jenkin Schibel</a> -
   <a href="https://github.com/jiangplus">jiangplus</a> -
   <a href="https://github.com/hunkyjimpjorps">Jimpjorps™</a> -
   <a href="https://github.com/joeykilpatrick">Joey Kilpatrick</a> -
@@ -208,6 +209,7 @@ Thank you to our sponsors! Gleam would not be possible without you.
   <a href="https://github.com/JonasHedEng">Jonas Hedman Engström</a> -
   <a href="https://github.com/jooaf">jooaf</a> -
   <a href="https://github.com/joseph-lozano">Joseph Lozano</a> -
+  <a href="https://github.com/JosephTLyons">Joseph T. Lyons</a> -
   <a href="https://github.com/joshocalico">Joshua Steele</a> -
   <a href="https://liberapay.com/d2quadra/">Julian Lukwata</a> -
   <a href="https://github.com/schurhammer">Julian Schurhammer</a> -
@@ -218,7 +220,6 @@ Thank you to our sponsors! Gleam would not be possible without you.
   <a href="https://github.com/kevinschweikert">Kevin Schweikert</a> -
   <a href="https://github.com/kodumbeats">kodumbeats</a> -
   <a href="https://github.com/hamptokr">Kramer Hampton</a> -
-  <a href="https://github.com/krautkai">krautkai</a> -
   <a href="https://github.com/Bearfinn">Kritsada Sunthornwutthikrai</a> -
   <a href="https://github.com/krystofrezac">Kryštof Řezáč</a> -
   <a href="https://github.com/krzysztofgb">Krzysztof G.</a> -
@@ -271,6 +272,7 @@ Thank you to our sponsors! Gleam would not be possible without you.
   <a href="https://github.com/nathanielknight">Nathaniel Knight</a> -
   <a href="https://github.com/Kuuuuuuuu">Nayuki</a> -
   <a href="https://github.com/NFIBrokerage">NFIBrokerage</a> -
+  <a href="https://github.com/arcanemachine">Nicholas Moen</a> -
   <a href="https://github.com/nchapman">Nick Chapman</a> -
   <a href="https://github.com/ndreynolds">Nick Reynolds</a> -
   <a href="https://github.com/NicklasXYZ">Nicklas Sindlev Andersen</a> -
diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs
index 8bd6799da..eeebc00a0 100644
--- a/compiler-core/src/parse.rs
+++ b/compiler-core/src/parse.rs
@@ -3284,16 +3284,33 @@ functions are declared separately from types.";
 
     // Expect a target name. e.g. `javascript` or `erlang`
     fn expect_target(&mut self) -> Result<Target, ParseError> {
-        let (_, t, _) = match self.next_tok() {
+        let (start, t, end) = match self.next_tok() {
             Some(t) => t,
             None => {
                 return parse_error(ParseErrorType::UnexpectedEof, SrcSpan { start: 0, end: 0 })
             }
         };
         match t {
-            Token::Name { name } => match Target::from_str(&name) {
-                Ok(target) => Ok(target),
-                Err(_) => self.next_tok_unexpected(Target::variant_strings()),
+            Token::Name { name } => match name.as_str() {
+                "javascript" => Ok(Target::JavaScript),
+                "erlang" => Ok(Target::Erlang),
+                "js" => {
+                    self.warnings
+                        .push(DeprecatedSyntaxWarning::DeprecatedTargetShorthand {
+                            location: SrcSpan { start, end },
+                            target: Target::JavaScript,
+                        });
+                    Ok(Target::JavaScript)
+                }
+                "erl" => {
+                    self.warnings
+                        .push(DeprecatedSyntaxWarning::DeprecatedTargetShorthand {
+                            location: SrcSpan { start, end },
+                            target: Target::Erlang,
+                        });
+                    Ok(Target::Erlang)
+                }
+                _ => self.next_tok_unexpected(Target::variant_strings()),
             },
             _ => self.next_tok_unexpected(Target::variant_strings()),
         }
diff --git a/compiler-core/src/warning.rs b/compiler-core/src/warning.rs
index 51240c354..4031c7764 100644
--- a/compiler-core/src/warning.rs
+++ b/compiler-core/src/warning.rs
@@ -1,5 +1,6 @@
 use crate::{
     ast::{SrcSpan, TodoKind},
+    build::Target,
     diagnostic::{self, Diagnostic, Location},
     error::wrap,
     type_::{
@@ -167,7 +168,9 @@ pub enum Warning {
 pub enum DeprecatedSyntaxWarning {
     /// If someone uses the deprecated syntax to append to a list:
     /// `["a"..rest]`, notice how there's no comma!
-    DeprecatedListPrepend { location: SrcSpan },
+    DeprecatedListPrepend {
+        location: SrcSpan,
+    },
 
     /// If someone uses the deprecated syntax to pattern match on a list:
     /// ```gleam
@@ -178,7 +181,9 @@ pub enum DeprecatedSyntaxWarning {
     /// }
     /// ```
     ///
-    DeprecatedListPattern { location: SrcSpan },
+    DeprecatedListPattern {
+        location: SrcSpan,
+    },
 
     /// If someone uses the deprecated syntax to match on all lists instead of
     /// a common `_`:
@@ -190,7 +195,9 @@ pub enum DeprecatedSyntaxWarning {
     /// }
     /// ```
     ///
-    DeprecatedListCatchAllPattern { location: SrcSpan },
+    DeprecatedListCatchAllPattern {
+        location: SrcSpan,
+    },
 
     /// If a record pattern has a spread that is not preceded by a comma:
     /// ```gleam
@@ -200,7 +207,14 @@ pub enum DeprecatedSyntaxWarning {
     /// }
     /// ```
     ///
-    DeprecatedRecordSpreadPattern { location: SrcSpan },
+    DeprecatedRecordSpreadPattern {
+        location: SrcSpan,
+    },
+
+    DeprecatedTargetShorthand {
+        target: Target,
+        location: SrcSpan,
+    },
 }
 
 impl Warning {
@@ -311,6 +325,35 @@ To match on all possible lists, use the `_` catch-all pattern instead.",
                 }),
             },
 
+            Warning::DeprecatedSyntax {
+                path,
+                src,
+                warning: DeprecatedSyntaxWarning::DeprecatedTargetShorthand { location, target },
+            } => {
+                let full_name = match target {
+                    Target::Erlang => "erlang",
+                    Target::JavaScript => "javascript",
+                };
+
+                Diagnostic {
+                    title: "Deprecated target shorthand syntax".into(),
+                    text: wrap(&format!(
+                        "This shorthand target name is deprecated. Use the full name: `{full_name}` instead."
+                    )),
+                    hint: None,
+                    level: diagnostic::Level::Warning,
+                    location: Some(Location {
+                        label: diagnostic::Label {
+                            text: Some(format!("This should be replaced with `{full_name}`")),
+                            span: *location,
+                        },
+                        path: path.clone(),
+                        src: src.clone(),
+                        extra_labels: vec![],
+                    }),
+                }
+            }
+
             Self::Type { path, warning, src } => match warning {
                 type_::Warning::Todo {
                     kind,


Test patch:
diff --git a/compiler-core/src/format/tests/conditional_compilation.rs b/compiler-core/src/format/tests/conditional_compilation.rs
index 19282de3f..1e7b3c7f2 100644
--- a/compiler-core/src/format/tests/conditional_compilation.rs
+++ b/compiler-core/src/format/tests/conditional_compilation.rs
@@ -1,4 +1,4 @@
-use crate::assert_format;
+use crate::{assert_format, assert_format_rewrite};
 
 #[test]
 fn multiple() {
@@ -17,3 +17,33 @@ type Z {
 "
     );
 }
+
+#[test]
+fn formatter_removes_target_shorthand_erlang() {
+    assert_format_rewrite!(
+        "@target(erl)
+fn wibble() {
+  todo
+}",
+        "@target(erlang)
+fn wibble() {
+  todo
+}
+"
+    );
+}
+
+#[test]
+fn formatter_removes_target_shorthand_javascript() {
+    assert_format_rewrite!(
+        "@target(js)
+fn wibble() {
+  todo
+}",
+        "@target(javascript)
+fn wibble() {
+  todo
+}
+"
+    );
+}
diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_target_shorthand_erlang.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_target_shorthand_erlang.snap
new file mode 100644
index 000000000..bbd286d01
--- /dev/null
+++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_target_shorthand_erlang.snap
@@ -0,0 +1,19 @@
+---
+source: compiler-core/src/type_/tests/warnings.rs
+expression: "\n@target(erl)\npub fn wibble() { panic }\n"
+---
+----- SOURCE CODE
+
+@target(erl)
+pub fn wibble() { panic }
+
+
+----- WARNING
+warning: Deprecated target shorthand syntax
+  ┌─ test/path:2:9
+  │
+2 │ @target(erl)
+  │         ^^^ This should be replaced with `erlang`
+
+This shorthand target name is deprecated. Use the full name: `erlang`
+instead.
diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_target_shorthand_javascript.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_target_shorthand_javascript.snap
new file mode 100644
index 000000000..b8a458b32
--- /dev/null
+++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__deprecated_target_shorthand_javascript.snap
@@ -0,0 +1,19 @@
+---
+source: compiler-core/src/type_/tests/warnings.rs
+expression: "\n@target(js)\npub fn wibble() { panic }\n"
+---
+----- SOURCE CODE
+
+@target(js)
+pub fn wibble() { panic }
+
+
+----- WARNING
+warning: Deprecated target shorthand syntax
+  ┌─ test/path:2:9
+  │
+2 │ @target(js)
+  │         ^^ This should be replaced with `javascript`
+
+This shorthand target name is deprecated. Use the full name: `javascript`
+instead.
diff --git a/compiler-core/src/type_/tests/warnings.rs b/compiler-core/src/type_/tests/warnings.rs
index f657aa3cc..7407723cd 100644
--- a/compiler-core/src/type_/tests/warnings.rs
+++ b/compiler-core/src/type_/tests/warnings.rs
@@ -2720,3 +2720,23 @@ pub fn main() {
 "#
     );
 }
+
+#[test]
+fn deprecated_target_shorthand_erlang() {
+    assert_warning!(
+        "
+@target(erl)
+pub fn wibble() { panic }
+"
+    );
+}
+
+#[test]
+fn deprecated_target_shorthand_javascript() {
+    assert_warning!(
+        "
+@target(js)
+pub fn wibble() { panic }
+"
+    );
+}