Skip to content

Commit

Permalink
feat(typescript): parse 'export as namespace' statements
Browse files Browse the repository at this point in the history
  • Loading branch information
strager committed Nov 4, 2023
1 parent 48c2557 commit 7b78dca
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 5 deletions.
7 changes: 7 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
quick-lint-js' version numbers are arbitrary. quick-lint-js does *not* adhere to
Semantic Versioning.

## Unreleased

### Added

* TypeScript support (still experimental):
* `export as namespace` statements are now parsed.

## 2.18.0 (2023-11-03)

[Downloads](https://c.quick-lint-js.com/releases/2.18.0/)
Expand Down
12 changes: 12 additions & 0 deletions po/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1409,6 +1409,18 @@ msgstr ""
msgid "{1:headlinese} value must be a compile-time constant"
msgstr ""

#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp
msgid "'export as namespace' is not allowed in a namespace or module"
msgstr ""

#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp
msgid "containing namespace or module declared here"
msgstr ""

#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp
msgid "'export as namespace' is only allowed in TypeScript .d.ts files"
msgstr ""

#: src/quick-lint-js/diag/diagnostic-metadata-generated.cpp
msgid "'export =' is not allowed; write 'export default' or 'module.exports =' (CommonJS) instead"
msgstr ""
Expand Down
32 changes: 32 additions & 0 deletions src/quick-lint-js/diag/diagnostic-metadata-generated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4189,6 +4189,38 @@ const QLJS_CONSTINIT Diagnostic_Info all_diagnostic_infos[] = {
},
},

// Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module
{
.code = 424,
.severity = Diagnostic_Severity::error,
.message_formats = {
QLJS_TRANSLATABLE("'export as namespace' is not allowed in a namespace or module"),
QLJS_TRANSLATABLE("containing namespace or module declared here"),
},
.message_args = {
{
Diagnostic_Message_Arg_Info(offsetof(Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module, export_keyword), Diagnostic_Arg_Type::source_code_span),
},
{
Diagnostic_Message_Arg_Info(offsetof(Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module, namespace_or_module_keyword), Diagnostic_Arg_Type::source_code_span),
},
},
},

// Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File
{
.code = 423,
.severity = Diagnostic_Severity::error,
.message_formats = {
QLJS_TRANSLATABLE("'export as namespace' is only allowed in TypeScript .d.ts files"),
},
.message_args = {
{
Diagnostic_Message_Arg_Info(offsetof(Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File, export_keyword), Diagnostic_Arg_Type::source_code_span),
},
},
},

// Diag_TypeScript_Export_Equal_Not_Allowed_In_JavaScript
{
.code = 370,
Expand Down
4 changes: 3 additions & 1 deletion src/quick-lint-js/diag/diagnostic-metadata-generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ namespace quick_lint_js {
QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Enum_Is_Not_Allowed_In_JavaScript) \
QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Enum_Member_Name_Cannot_Be_Number) \
QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Enum_Value_Must_Be_Constant) \
QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module) \
QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File) \
QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Export_Equal_Not_Allowed_In_JavaScript) \
QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Import_Type_Missing_Export_Name) \
QLJS_DIAG_TYPE_NAME(Diag_TypeScript_Implements_Must_Be_After_Extends) \
Expand Down Expand Up @@ -444,7 +446,7 @@ namespace quick_lint_js {
/* END */
// clang-format on

inline constexpr int Diag_Type_Count = 430;
inline constexpr int Diag_Type_Count = 432;

extern const Diagnostic_Info all_diagnostic_infos[Diag_Type_Count];
}
Expand Down
21 changes: 21 additions & 0 deletions src/quick-lint-js/diag/diagnostic-types-2.h
Original file line number Diff line number Diff line change
Expand Up @@ -2155,6 +2155,27 @@ struct Diag_TypeScript_Enum_Value_Must_Be_Constant {
Enum_Kind declared_enum_kind;
};

struct
Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module {
[[qljs::diag("E0424", Diagnostic_Severity::error)]] //
[[qljs::message(
"'export as namespace' is not allowed in a namespace or module",
ARG(export_keyword))]] //
[[qljs::message("containing namespace or module declared here",
ARG(namespace_or_module_keyword))]] //
Source_Code_Span export_keyword;
Source_Code_Span namespace_or_module_keyword;
};

struct
Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File {
[[qljs::diag("E0423", Diagnostic_Severity::error)]] //
[[qljs::message(
"'export as namespace' is only allowed in TypeScript .d.ts files",
ARG(export_keyword))]] //
Source_Code_Span export_keyword;
};

struct Diag_TypeScript_Export_Equal_Not_Allowed_In_JavaScript {
[[qljs::diag("E0370", Diagnostic_Severity::error)]] //
// clang-format off
Expand Down
31 changes: 31 additions & 0 deletions src/quick-lint-js/fe/parse-statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,37 @@ void Parser::parse_and_visit_export(Parse_Visitor_Base &v,
break;
}

// export as namespace MyLibrary; // TypeScript definition only.
case Token_Type::kw_as:
// @@@ declare namespace stuff
this->skip();
QLJS_PARSER_UNIMPLEMENTED_IF_NOT_TOKEN(Token_Type::kw_namespace);
this->skip();
switch (this->peek().type) {
QLJS_CASE_CONTEXTUAL_KEYWORD:
case Token_Type::identifier:
this->skip();
break;
default:
QLJS_PARSER_UNIMPLEMENTED();
break;
}
if (!this->options_.typescript_definition_file) {
this->diag_reporter_->report(
Diag_TypeScript_Export_As_Namespace_Is_Only_Allowed_In_TypeScript_Definition_File{
.export_keyword = export_token_span,
});
} else if (this->in_typescript_namespace_or_module_.has_value()) {
this->diag_reporter_->report(
Diag_TypeScript_Export_As_Namespace_Is_Not_Allowed_In_Namespace_Or_Module{
.export_keyword = export_token_span,
.namespace_or_module_keyword =
*this->in_typescript_namespace_or_module_,
});
}
this->consume_semicolon_after_statement();
break;

// export enum E {} // TypeScript only.
case Token_Type::kw_enum:
// is_current_typescript_namespace_non_empty_ is possibly set by
Expand Down
8 changes: 7 additions & 1 deletion src/quick-lint-js/i18n/translation-table-generated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ const Translation_Table translation_data = {
{18, 13, 53, 16, 51, 16}, //
{0, 0, 0, 0, 0, 33}, //
{0, 0, 0, 0, 0, 91}, //
{0, 0, 0, 0, 0, 62}, //
{0, 0, 0, 0, 0, 64}, //
{0, 0, 0, 39, 0, 22}, //
{30, 39, 0, 46, 0, 38}, //
{0, 0, 0, 0, 0, 11}, //
Expand Down Expand Up @@ -222,7 +224,8 @@ const Translation_Table translation_data = {
{58, 31, 67, 69, 0, 43}, //
{90, 38, 91, 90, 53, 75}, //
{0, 0, 0, 0, 0, 29}, //
{41, 16, 34, 35, 34, 43}, //
{0, 0, 0, 0, 0, 43}, //
{41, 16, 34, 35, 34, 45}, //
{0, 0, 0, 0, 0, 43}, //
{0, 0, 0, 0, 0, 60}, //
{0, 0, 0, 0, 0, 22}, //
Expand Down Expand Up @@ -1862,6 +1865,8 @@ const Translation_Table translation_data = {
u8"'do-while' loop\0"
u8"'else' has no corresponding 'if'\0"
u8"'export =' is not allowed; write 'export default' or 'module.exports =' (CommonJS) instead\0"
u8"'export as namespace' is not allowed in a namespace or module\0"
u8"'export as namespace' is only allowed in TypeScript .d.ts files\0"
u8"'export' keyword here\0"
u8"'extends' must be before 'implements'\0"
u8"'for' loop\0"
Expand Down Expand Up @@ -2019,6 +2024,7 @@ const Translation_Table translation_data = {
u8"const fields within classes are only allowed in TypeScript, not JavaScript\0"
u8"const variable declared here\0"
u8"containing 'declare namespace' starts here\0"
u8"containing namespace or module declared here\0"
u8"continue can only be used inside of a loop\0"
u8"decorator belongs immediately before this overloaded method\0"
u8"decorator starts here\0"
Expand Down
7 changes: 5 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 = 526;
constexpr std::size_t translation_table_string_table_size = 80133;
constexpr std::uint16_t translation_table_mapping_table_size = 529;
constexpr std::size_t translation_table_string_table_size = 80304;
constexpr std::size_t translation_table_locale_table_size = 35;

QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up(
Expand Down Expand Up @@ -80,6 +80,8 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up(
"'do-while' loop"sv,
"'else' has no corresponding 'if'"sv,
"'export =' is not allowed; write 'export default' or 'module.exports =' (CommonJS) instead"sv,
"'export as namespace' is not allowed in a namespace or module"sv,
"'export as namespace' is only allowed in TypeScript .d.ts files"sv,
"'export' keyword here"sv,
"'extends' must be before 'implements'"sv,
"'for' loop"sv,
Expand Down Expand Up @@ -237,6 +239,7 @@ QLJS_CONSTEVAL std::uint16_t translation_table_const_look_up(
"const fields within classes are only allowed in TypeScript, not JavaScript"sv,
"const variable declared here"sv,
"containing 'declare namespace' starts here"sv,
"containing namespace or module declared here"sv,
"continue can only be used inside of a loop"sv,
"decorator belongs immediately before this overloaded method"sv,
"decorator starts here"sv,
Expand Down
35 changes: 34 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[525] = {
inline const Translated_String test_translation_table[528] = {
{
"\"global-groups\" entries must be strings"_translatable,
u8"\"global-groups\" entries must be strings",
Expand Down Expand Up @@ -622,6 +622,28 @@ inline const Translated_String test_translation_table[525] = {
u8"'export =' is not allowed; write 'export default' or 'module.exports =' (CommonJS) instead",
},
},
{
"'export as namespace' is not allowed in a namespace or module"_translatable,
u8"'export as namespace' is not allowed in a namespace or module",
{
u8"'export as namespace' is not allowed in a namespace or module",
u8"'export as namespace' is not allowed in a namespace or module",
u8"'export as namespace' is not allowed in a namespace or module",
u8"'export as namespace' is not allowed in a namespace or module",
u8"'export as namespace' is not allowed in a namespace or module",
},
},
{
"'export as namespace' is only allowed in TypeScript .d.ts files"_translatable,
u8"'export as namespace' is only allowed in TypeScript .d.ts files",
{
u8"'export as namespace' is only allowed in TypeScript .d.ts files",
u8"'export as namespace' is only allowed in TypeScript .d.ts files",
u8"'export as namespace' is only allowed in TypeScript .d.ts files",
u8"'export as namespace' is only allowed in TypeScript .d.ts files",
u8"'export as namespace' is only allowed in TypeScript .d.ts files",
},
},
{
"'export' keyword here"_translatable,
u8"'export' keyword here",
Expand Down Expand Up @@ -2349,6 +2371,17 @@ inline const Translated_String test_translation_table[525] = {
u8"containing 'declare namespace' starts here",
},
},
{
"containing namespace or module declared here"_translatable,
u8"containing namespace or module declared here",
{
u8"containing namespace or module declared here",
u8"containing namespace or module declared here",
u8"containing namespace or module declared here",
u8"containing namespace or module declared here",
u8"containing namespace or module declared here",
},
},
{
"continue can only be used inside of a loop"_translatable,
u8"continue can only be used inside of a loop",
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ quick_lint_js_add_executable(
test-parse-typescript-declare-function.cpp
test-parse-typescript-declare-global.cpp
test-parse-typescript-declare-interface.cpp
test-parse-typescript-declare-module.cpp
test-parse-typescript-declare-namespace.cpp
test-parse-typescript-declare-tsmodule.cpp
test-parse-typescript-declare-type-alias.cpp
Expand Down
Loading

0 comments on commit 7b78dca

Please sign in to comment.