Skip to content

Commit

Permalink
Split transformations
Browse files Browse the repository at this point in the history
  • Loading branch information
CPunisher committed Nov 13, 2024
1 parent b98e2eb commit 49c2be0
Show file tree
Hide file tree
Showing 8 changed files with 899 additions and 738 deletions.
4 changes: 1 addition & 3 deletions crates/swc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -988,10 +988,8 @@ impl Compiler {
let issues = checker.transform(&mut program);

for issue in issues {
let range = issue.range();

handler
.struct_span_err(range.span, &issue.to_string())
.struct_span_err(issue.range.span, &issue.message)
.emit();
}

Expand Down
193 changes: 171 additions & 22 deletions crates/swc_typescript/src/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,184 @@
use std::sync::Arc;
//! References
//! * </~https://github.com/oxc-project/oxc/blob/main/crates/oxc_isolated_declarations/src/diagnostics.rs>
use std::{borrow::Cow, sync::Arc};

use swc_common::{FileName, Span};

use crate::fast_dts::FastDts;

#[derive(Debug, Clone)]
pub struct SourceRange {
pub filename: Arc<FileName>,
pub span: Span,
}

#[derive(Debug, Clone, thiserror::Error)]
pub enum DtsIssue {
#[error("unable to infer type from expression or declaration")]
UnableToInferType { range: SourceRange },
#[error("unable to infer type, falling back to any type")]
UnableToInferTypeFallbackAny { range: SourceRange },
#[error("unable to infer type from object property, skipping")]
UnableToInferTypeFromProp { range: SourceRange },
#[error("unable to infer type from spread, skipping")]
UnableToInferTypeFromSpread { range: SourceRange },
#[error("cannot infer type from using, skipping")]
UnsupportedUsing { range: SourceRange },
#[derive(Debug, Clone)]
pub struct DtsIssue {
pub range: SourceRange,
pub message: Cow<'static, str>,
}

impl DtsIssue {
pub fn range(&self) -> &SourceRange {
match self {
DtsIssue::UnableToInferType { range } => range,
DtsIssue::UnableToInferTypeFallbackAny { range } => range,
DtsIssue::UnableToInferTypeFromProp { range } => range,
DtsIssue::UnableToInferTypeFromSpread { range } => range,
DtsIssue::UnsupportedUsing { range } => range,
}
impl FastDts {
pub fn function_must_have_explicit_return_type(&mut self, span: Span) {
self.mark_diagnostic(
"TS9007: Function must have an explicit return type annotation with \
--isolatedDeclarations.",
span,
);
}

pub fn method_must_have_explicit_return_type(&mut self, span: Span) {
self.mark_diagnostic(
"TS9008: Method must have an explicit return type annotation with \
--isolatedDeclarations.",
span,
);
}

pub fn accessor_must_have_explicit_return_type(&mut self, span: Span) {
self.mark_diagnostic(
"TS9009: At least one accessor must have an explicit return type annotation with \
--isolatedDeclarations.",
span,
);
}

pub fn variable_must_have_explicit_type(&mut self, span: Span) {
self.mark_diagnostic(
"TS9010: Variable must have an explicit type annotation with --isolatedDeclarations.",
span,
);
}

pub fn parameter_must_have_explicit_type(&mut self, span: Span) {
self.mark_diagnostic(
"TS9011: Parameter must have an explicit type annotation with --isolatedDeclarations.",
span,
);
}

pub fn property_must_have_explicit_type(&mut self, span: Span) {
self.mark_diagnostic(
"TS9012: Property must have an explicit type annotation with --isolatedDeclarations.",
span,
);
}

pub fn inferred_type_of_expression(&mut self, span: Span) {
self.mark_diagnostic(
"TS9013: Expression type can't be inferred with --isolatedDeclarations.",
span,
);
}

pub fn signature_computed_property_name(&mut self, span: Span) {
self.mark_diagnostic(
"TS9014: Computed properties must be number or string literals, variables or dotted \
expressions with --isolatedDeclarations.",
span,
);
}

pub fn object_with_spread_assignments(&mut self, span: Span) {
self.mark_diagnostic(
"TS9015: Objects that contain spread assignments can't be inferred with \
--isolatedDeclarations.",
span,
);
}

pub fn shorthand_property(&mut self, span: Span) {
self.mark_diagnostic(
"TS9016: Objects that contain shorthand properties can't be inferred with \
--isolatedDeclarations.",
span,
);
}

pub fn array_inferred(&mut self, span: Span) {
self.mark_diagnostic(
"TS9017: Only const arrays can be inferred with --isolatedDeclarations.",
span,
);
}

pub fn arrays_with_spread_elements(&mut self, span: Span) {
self.mark_diagnostic(
"TS9018: Arrays with spread elements can't inferred with --isolatedDeclarations.",
span,
);
}

pub fn binding_element_export(&mut self, span: Span) {
self.mark_diagnostic(
"TS9019: Binding elements can't be exported directly with --isolatedDeclarations.",
span,
);
}

pub fn enum_member_initializers(&mut self, span: Span) {
self.mark_diagnostic(
"TS9020: Enum member initializers must be computable without references to external \
symbols with --isolatedDeclarations.",
span,
);
}

pub fn extends_clause_expression(&mut self, span: Span) {
self.mark_diagnostic(
"TS9021: Extends clause can't contain an expression with --isolatedDeclarations.",
span,
);
}

pub fn inferred_type_of_class_expression(&mut self, span: Span) {
self.mark_diagnostic(
"TS9022: Inference from class expressions is not supported with \
--isolatedDeclarations.",
span,
);
}

pub fn implicitly_adding_undefined_to_type(&mut self, span: Span) {
self.mark_diagnostic(
"TS9025: Declaration emit for this parameter requires implicitly adding undefined to \
it's type. This is not supported with --isolatedDeclarations.",
span,
);
}

pub fn function_with_assigning_properties(&mut self, span: Span) {
self.mark_diagnostic(
"TS9023: Assigning properties to functions without declaring them is not supported \
with --isolatedDeclarations. Add an explicit declaration for the properties assigned \
to this function.",
span,
);
}

pub fn default_export_inferred(&mut self, span: Span) {
self.mark_diagnostic(
"TS9037: Default exports can't be inferred with --isolatedDeclarations.",
span,
);
}

pub fn computed_property_name(&mut self, span: Span) {
self.mark_diagnostic(
"TS9038: Computed property names on class or object literals cannot be inferred with \
--isolatedDeclarations.",
span,
);
}

pub fn type_containing_private_name(&mut self, name: &str, span: Span) {
self.mark_diagnostic(
format!(
"TS9039: Type containing private name '{name}' can't be used with \
--isolatedDeclarations."
),
span,
);
}
}
109 changes: 109 additions & 0 deletions crates/swc_typescript/src/fast_dts/class.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use swc_common::util::take::Take;
use swc_ecma_ast::{Class, ClassMember, MethodKind};

use super::{any_type_ann, type_ann, valid_prop_name, FastDts};

impl FastDts {
pub(crate) fn transform_class(&mut self, class: &mut Class) {
// Track if the previous member was an overload signature or not.
// When overloads are present the last item has the implementation
// body. For declaration files the implementation always needs to
// be dropped. Needs to be unique for each class because another
// class could be created inside a class method.
let mut prev_is_overload = false;

let new_body = class
.body
.take()
.into_iter()
.filter(|member| match member {
ClassMember::Constructor(class_constructor) => {
let is_overload =
class_constructor.body.is_none() && !class_constructor.is_optional;
if !prev_is_overload || is_overload {
prev_is_overload = is_overload;
true
} else {
prev_is_overload = false;
false
}
}
ClassMember::Method(method) => {
let is_overload = method.function.body.is_none()
&& !(method.is_abstract || method.is_optional);
if !prev_is_overload || is_overload {
prev_is_overload = is_overload;
true
} else {
prev_is_overload = false;
false
}
}
ClassMember::TsIndexSignature(_)
| ClassMember::ClassProp(_)
| ClassMember::PrivateProp(_)
| ClassMember::Empty(_)
| ClassMember::StaticBlock(_)
| ClassMember::AutoAccessor(_)
| ClassMember::PrivateMethod(_) => {
prev_is_overload = false;
true
}
})
.filter_map(|member| match member {
ClassMember::Constructor(mut class_constructor) => {
class_constructor.body = None;
self.handle_ts_param_props(&mut class_constructor.params);
Some(ClassMember::Constructor(class_constructor))
}
ClassMember::Method(mut method) => {
if let Some(new_prop_name) = valid_prop_name(&method.key) {
method.key = new_prop_name;
} else {
return None;
}

method.function.body = None;
if method.kind == MethodKind::Setter {
method.function.return_type = None;
}
self.transform_fn_params(&mut method.function.params);
Some(ClassMember::Method(method))
}
ClassMember::ClassProp(mut prop) => {
if let Some(new_prop_name) = valid_prop_name(&prop.key) {
prop.key = new_prop_name;
} else {
return None;
}

if prop.type_ann.is_none() {
if let Some(value) = prop.value {
prop.type_ann = self
.infer_type_from_expr(&value, false, false)
.map(type_ann)
.or_else(|| Some(any_type_ann()));
}
}
prop.value = None;
prop.definite = false;
prop.declare = false;

Some(ClassMember::ClassProp(prop))
}
ClassMember::TsIndexSignature(index_sig) => {
Some(ClassMember::TsIndexSignature(index_sig))
}

// These can be removed as they are not relevant for types
ClassMember::PrivateMethod(_)
| ClassMember::PrivateProp(_)
| ClassMember::Empty(_)
| ClassMember::StaticBlock(_)
| ClassMember::AutoAccessor(_) => None,
})
.collect();

class.body = new_body;
}
}
Loading

0 comments on commit 49c2be0

Please sign in to comment.