Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(typescript): add new diag for "import type" with import alias #1140

Merged
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
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
koopiehoop marked this conversation as resolved.
Show resolved Hide resolved
}));
}
}

TEST_F(Test_Parse_TypeScript_Namespace,
namespace_alias_cannot_be_used_with_declare_keyword) {
{
Expand Down
Loading