Skip to content

Commit

Permalink
feat(typescript): allow 'export default I; interface I {}'
Browse files Browse the repository at this point in the history
Allow 'export default' to find TypeScript types (such as interfaces),
not just run-time variables.
  • Loading branch information
strager committed Nov 21, 2023
1 parent 1c03c4f commit d85ec29
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 10 deletions.
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Semantic Versioning.
an arrow function parameter list.
* If a type predicate appears outside a return type, quick-lint-js now reports
[E0426][] ("type predicates are only allowed as function return types").
* `export default` now supports separately-declared TypeScript interfaces and
types.

### Fixed

Expand Down
33 changes: 23 additions & 10 deletions src/quick-lint-js/fe/variable-analyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,12 +467,22 @@ void Variable_Analyzer::visit_variable_use(Identifier name,
Used_Variable_Kind use_kind) {
QLJS_ASSERT(!this->scopes_.empty());
Scope &current_scope = this->current_scope();
Declared_Variable *var =
use_kind == Used_Variable_Kind::type
? current_scope.declared_variables.find_type(name)
: use_kind == Used_Variable_Kind::_export
? current_scope.declared_variables.find(name)
: current_scope.declared_variables.find_runtime(name);
Declared_Variable *var;
switch (use_kind) {
case Used_Variable_Kind::type:
var = current_scope.declared_variables.find_type(name);
break;
case Used_Variable_Kind::_export:
case Used_Variable_Kind::_export_default:
var = current_scope.declared_variables.find(name);
break;
case Used_Variable_Kind::_delete:
case Used_Variable_Kind::_typeof:
case Used_Variable_Kind::assignment:
case Used_Variable_Kind::use:
var = current_scope.declared_variables.find_runtime(name);
break;
}
if (var) {
var->is_used = true;
} else {
Expand Down Expand Up @@ -534,12 +544,15 @@ void Variable_Analyzer::visit_end_of_module() {
switch (var.kind) {
case Used_Variable_Kind::_delete:
case Used_Variable_Kind::_export:
case Used_Variable_Kind::_export_default:
case Used_Variable_Kind::_typeof:
case Used_Variable_Kind::assignment:
case Used_Variable_Kind::use:
QLJS_ASSERT(!global_scope.declared_variables.find_runtime(var.name));
break;
case Used_Variable_Kind::_export_default:
QLJS_ASSERT(!global_scope.declared_variables.find_runtime(var.name));
QLJS_ASSERT(!global_scope.declared_variables.find_type(var.name));
break;
case Used_Variable_Kind::type:
QLJS_ASSERT(!global_scope.declared_variables.find_type(var.name));
break;
Expand Down Expand Up @@ -644,11 +657,11 @@ void Variable_Analyzer::propagate_variable_uses_to_parent_scope(
Found_Variable_Type var = {};
switch (used_var.kind) {
case Used_Variable_Kind::_export:
case Used_Variable_Kind::_export_default:
QLJS_ASSERT(!current_scope.declared_variables.find(used_var.name));
var = parent_scope.declared_variables.find(used_var.name);
break;
case Used_Variable_Kind::_delete:
case Used_Variable_Kind::_export_default:
case Used_Variable_Kind::_typeof:
case Used_Variable_Kind::assignment:
case Used_Variable_Kind::use:
Expand Down Expand Up @@ -688,10 +701,10 @@ void Variable_Analyzer::propagate_variable_uses_to_parent_scope(
Found_Variable_Type var = {};
switch (used_var.kind) {
case Used_Variable_Kind::_export:
case Used_Variable_Kind::_export_default:
var = parent_scope.declared_variables.find(used_var.name);
break;
case Used_Variable_Kind::_delete:
case Used_Variable_Kind::_export_default:
case Used_Variable_Kind::_typeof:
case Used_Variable_Kind::assignment:
case Used_Variable_Kind::use:
Expand Down Expand Up @@ -1174,10 +1187,10 @@ bool Variable_Analyzer::Used_Variable::is_runtime() const {
bool Variable_Analyzer::Used_Variable::is_type() const {
switch (this->kind) {
case Used_Variable_Kind::_export:
case Used_Variable_Kind::_export_default:
case Used_Variable_Kind::type:
return true;
case Used_Variable_Kind::_delete:
case Used_Variable_Kind::_export_default:
case Used_Variable_Kind::_typeof:
case Used_Variable_Kind::assignment:
case Used_Variable_Kind::use:
Expand Down
24 changes: 24 additions & 0 deletions test/test-variable-analyzer-module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,30 @@ TEST(
u8"declare module 'm' { export default C; class C {} }"_sv, no_diags,
typescript_analyze_options, default_globals);
}

TEST(Test_Variable_Analyzer_Module,
variable_export_can_export_typescript_types) {
test_parse_and_analyze(u8"interface I {}; export {I};"_sv, no_diags,
typescript_analyze_options, default_globals);
test_parse_and_analyze(u8"export {T}; type T = null;"_sv, no_diags,
typescript_analyze_options, default_globals);
}

TEST(Test_Variable_Analyzer_Module,
export_default_can_export_typescript_types_after_declaration) {
test_parse_and_analyze(u8"interface I {}; export default I;"_sv, no_diags,
typescript_analyze_options, default_globals);
test_parse_and_analyze(u8"type T = null; export default T;"_sv, no_diags,
typescript_analyze_options, default_globals);
}

TEST(Test_Variable_Analyzer_Module,
export_default_can_export_typescript_types_before_declaration) {
test_parse_and_analyze(u8"export default I; interface I {}"_sv, no_diags,
typescript_analyze_options, default_globals);
test_parse_and_analyze(u8"export default T; type T = null;"_sv, no_diags,
typescript_analyze_options, default_globals);
}
}
}

Expand Down

0 comments on commit d85ec29

Please sign in to comment.