Skip to content

Commit

Permalink
feat(typescript): add new diag for "import type" with namespace alias
Browse files Browse the repository at this point in the history
  • Loading branch information
koopiehoop authored and strager committed Jan 3, 2024
1 parent b05e1cc commit c081fed
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 9 deletions.
19 changes: 19 additions & 0 deletions docs/errors/E0717.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# E0717: namespace alias cannot use 'import type'


The error message "namespace alias cannot use 'import type'" occurs when
trying to use the 'import type' syntax with an alias.


```typescript
import type A = ns;
```


To fix this error, you need to use the regular 'import' syntax instead
of 'import type' when using an alias.


```typescript
import A = ns;
```
4 changes: 4 additions & 0 deletions po/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -2401,6 +2401,10 @@ msgstr ""
msgid "'&' here"
msgstr ""

#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp
msgid "namespace alias cannot use 'import type'"
msgstr ""

#: test/test-diagnostic-formatter.cpp
#: test/test-vim-qflist-json-diag-reporter.cpp
msgid "something happened"
Expand Down
14 changes: 14 additions & 0 deletions src/quick-lint-js/diag/diagnostic-metadata-generated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6870,6 +6870,20 @@ const QLJS_CONSTINIT Diagnostic_Info all_diagnostic_infos[] = {
},
},
},

// Diag_TypeScript_Namespace_Alias_Cannot_Use_Import_Type
{
.code = 717,
.severity = Diagnostic_Severity::error,
.message_formats = {
QLJS_TRANSLATABLE("namespace alias cannot use 'import type'"),
},
.message_args = {
{
Diagnostic_Message_Arg_Info(offsetof(Diag_TypeScript_Namespace_Alias_Cannot_Use_Import_Type, type_keyword), Diagnostic_Arg_Type::source_code_span),
},
},
},
};
}

Expand Down
3 changes: 2 additions & 1 deletion src/quick-lint-js/diag/diagnostic-metadata-generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -469,10 +469,11 @@ namespace quick_lint_js {
QLJS_DIAG_TYPE_NAME(Diag_Class_Async_On_Getter_Or_Setter) \
QLJS_DIAG_TYPE_NAME(Diag_Multiple_Export_Defaults) \
QLJS_DIAG_TYPE_NAME(Diag_Unintuitive_Bitshift_Precedence) \
QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Namespace_Alias_Cannot_Use_Import_Type) \
/* END */
// clang-format on

inline constexpr int Diag_Type_Count = 458;
inline constexpr int Diag_Type_Count = 459;

extern const Diagnostic_Info all_diagnostic_infos[Diag_Type_Count];
}
Expand Down
7 changes: 7 additions & 0 deletions src/quick-lint-js/diag/diagnostic-types-2.h
Original file line number Diff line number Diff line change
Expand Up @@ -3567,6 +3567,13 @@ struct Diag_Unintuitive_Bitshift_Precedence {
Source_Code_Span bitshift_operator;
Source_Code_Span and_operator;
};

struct Diag_TypeScript_Namespace_Alias_Cannot_Use_Import_Type {
[[qljs::diag("E0717", Diagnostic_Severity::error)]] //
[[qljs::message("namespace alias cannot use 'import type'",
ARG(type_keyword))]] //
Source_Code_Span type_keyword;
};
}
QLJS_WARNING_POP

Expand Down
17 changes: 12 additions & 5 deletions src/quick-lint-js/fe/parse-statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4607,6 +4607,7 @@ void Parser::parse_and_visit_import(
}
};

std::optional<Source_Code_Span> type_span = std::nullopt;
switch (this->peek().type) {
// import var from "module"; // Invalid.
QLJS_CASE_RESERVED_KEYWORD_EXCEPT_AWAIT_AND_YIELD:
Expand Down Expand Up @@ -4703,12 +4704,12 @@ void Parser::parse_and_visit_import(
// import type from "module";
case Token_Type::kw_type: {
// Do not set is_current_typescript_namespace_non_empty_.
Source_Code_Span type_span = this->peek().span();
type_span = this->peek().span();
auto report_type_only_import_in_javascript_if_needed = [&] {
if (!this->options_.typescript) {
this->diag_reporter_->report(
Diag_TypeScript_Type_Import_Not_Allowed_In_JavaScript{
.type_keyword = type_span,
.type_keyword = *type_span,
});
}
};
Expand Down Expand Up @@ -4741,7 +4742,7 @@ void Parser::parse_and_visit_import(
case Token_Type::left_curly:
this->diag_reporter_->report(
Diag_TypeScript_Type_Only_Import_Cannot_Import_Default_And_Named{
.type_keyword = type_span,
.type_keyword = *type_span,
});
// Parse the named exports as if 'type' didn't exist. The user might
// be thinking that 'type' only applies to 'T' and not '{U}'.
Expand All @@ -4752,7 +4753,7 @@ void Parser::parse_and_visit_import(
case Token_Type::star:
this->diag_reporter_->report(
Diag_TypeScript_Type_Only_Import_Cannot_Import_Default_And_Named{
.type_keyword = type_span,
.type_keyword = *type_span,
});
this->parse_and_visit_name_space_import(v);
break;
Expand All @@ -4771,7 +4772,7 @@ void Parser::parse_and_visit_import(
this->lexer_.commit_transaction(std::move(transaction));
report_type_only_import_in_javascript_if_needed();
this->parse_and_visit_named_exports_for_typescript_type_only_import(
v, type_span);
v, *type_span);
break;

// import type * as M from "module"; // TypeScript only
Expand Down Expand Up @@ -4855,6 +4856,12 @@ void Parser::parse_and_visit_import(
QLJS_PARSER_UNIMPLEMENTED_IF_NOT_TOKEN(Token_Type::right_paren);
this->skip();
} else {
if (declared_variable_kind == Variable_Kind::_import_type) {
// import type a = b; // Invalid.
this->diag_reporter_->report(
Diag_TypeScript_Namespace_Alias_Cannot_Use_Import_Type{
.type_keyword = *type_span});
}
// import myns = ns;
// import C = ns.C;
declared_variable_kind = Variable_Kind::_import_alias;
Expand Down
2 changes: 2 additions & 0 deletions src/quick-lint-js/i18n/translation-table-generated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ const Translation_Table translation_data = {
{0, 0, 0, 0, 0, 51}, //
{0, 0, 0, 0, 0, 47}, //
{0, 0, 0, 0, 0, 10}, //
{0, 0, 0, 0, 0, 41}, //
{69, 26, 0, 59, 0, 22}, //
{0, 0, 0, 46, 0, 39}, //
{0, 0, 0, 0, 0, 40}, //
Expand Down Expand Up @@ -2324,6 +2325,7 @@ const Translation_Table translation_data = {
u8"move the 'extends' clause before 'implements' here\0"
u8"move the parameter decorator before '{0}' here\0"
u8"namespace\0"
u8"namespace alias cannot use 'import type'\0"
u8"namespace starts here\0"
u8"new variable shadows existing variable\0"
u8"newline is not allowed after 'abstract'\0"
Expand Down
5 changes: 3 additions & 2 deletions src/quick-lint-js/i18n/translation-table-generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ namespace quick_lint_js {
using namespace std::literals::string_view_literals;

constexpr std::uint32_t translation_table_locale_count = 5;
constexpr std::uint16_t translation_table_mapping_table_size = 602;
constexpr std::size_t translation_table_string_table_size = 82276;
constexpr std::uint16_t translation_table_mapping_table_size = 603;
constexpr std::size_t translation_table_string_table_size = 82317;
constexpr std::size_t translation_table_locale_table_size = 35;

QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up(
Expand Down Expand Up @@ -471,6 +471,7 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up(
"move the 'extends' clause before 'implements' here"sv,
"move the parameter decorator before '{0}' here"sv,
"namespace"sv,
"namespace alias cannot use 'import type'"sv,
"namespace starts here"sv,
"new variable shadows existing variable"sv,
"newline is not allowed after 'abstract'"sv,
Expand Down
13 changes: 12 additions & 1 deletion src/quick-lint-js/i18n/translation-table-test-generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct Translated_String {
};

// clang-format off
inline const Translated_String test_translation_table[601] = {
inline const Translated_String test_translation_table[602] = {
{
"\"global-groups\" entries must be strings"_translatable,
u8"\"global-groups\" entries must be strings",
Expand Down Expand Up @@ -4923,6 +4923,17 @@ inline const Translated_String test_translation_table[601] = {
u8"namespace",
},
},
{
"namespace alias cannot use 'import type'"_translatable,
u8"namespace alias cannot use 'import type'",
{
u8"namespace alias cannot use 'import type'",
u8"namespace alias cannot use 'import type'",
u8"namespace alias cannot use 'import type'",
u8"namespace alias cannot use 'import type'",
u8"namespace alias cannot use 'import type'",
},
},
{
"namespace starts here"_translatable,
u8"namespace starts here",
Expand Down
14 changes: 14 additions & 0 deletions test/test-parse-typescript-namespace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,20 @@ TEST_F(Test_Parse_TypeScript_Namespace,
}
}

TEST_F(Test_Parse_TypeScript_Namespace,
namespace_alias_cannot_use_import_type) {
{
Spy_Visitor p = test_parse_and_visit_statement(
u8"import type A = ns;"_sv, //
u8" ^^^^ Diag_TypeScript_Namespace_Alias_Cannot_Use_Import_Type.type_keyword"_diag,
typescript_options);
EXPECT_THAT(p.visits, ElementsAreArray({
"visit_variable_declaration", // A
"visit_variable_namespace_use", // ns
}));
}
}

TEST_F(Test_Parse_TypeScript_Namespace,
namespace_alias_cannot_be_used_with_declare_keyword) {
{
Expand Down

0 comments on commit c081fed

Please sign in to comment.