Skip to content

Commit

Permalink
refactor: improve
Browse files Browse the repository at this point in the history
  • Loading branch information
Dunqing committed Jun 14, 2024
1 parent 17cdab4 commit 909ab4d
Show file tree
Hide file tree
Showing 10 changed files with 790 additions and 747 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/oxc_transformer_dts/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "oxc_transformer_dts"
version = "0.13.5"
version = "0.0.0"
publish = true
authors.workspace = true
description.workspace = true
Expand All @@ -25,7 +25,7 @@ oxc_ast = { workspace = true }
oxc_span = { workspace = true }
oxc_allocator = { workspace = true }
oxc_diagnostics = { workspace = true }
oxc_syntax = { workspace = true, features = ["to_js_string"] }
oxc_syntax = { workspace = true }

rustc-hash = { workspace = true }

Expand Down
234 changes: 234 additions & 0 deletions crates/oxc_transformer_dts/src/class.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
#[allow(clippy::wildcard_imports)]
use oxc_ast::ast::*;

use oxc_allocator::Box;
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{GetSpan, SPAN};

use crate::TransformerDts;

impl<'a> TransformerDts<'a> {
pub fn report_property_key(&self, key: &PropertyKey<'a>, computed: bool) -> bool {
if computed
&& !matches!(
key,
PropertyKey::StringLiteral(_)
| PropertyKey::NumericLiteral(_)
| PropertyKey::BigintLiteral(_)
)
{
self.ctx.error(
OxcDiagnostic::error("Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.")
.with_label(key.span())
);
true
} else {
false
}
}

pub fn transform_accessibility(
&self,
accessibility: Option<TSAccessibility>,
) -> Option<TSAccessibility> {
if accessibility.is_none() || accessibility.is_some_and(|a| a == TSAccessibility::Public) {
None
} else {
accessibility
}
}

pub fn transform_class(&self, decl: &Class<'a>) -> Option<Box<'a, Class<'a>>> {
if decl.is_declare() {
return None;
}

let mut elements = self.ctx.ast.new_vec();
let mut has_private_key = false;
for element in &decl.body.body {
match element {
ClassElement::StaticBlock(_) => {}
ClassElement::MethodDefinition(definition) => {
if self.report_property_key(&definition.key, definition.computed) {
return None;
}
if definition.key.is_private_identifier() {
has_private_key = true;
}
let function = &definition.value;
let params = self.transform_formal_parameters(&function.params);

if definition.kind.is_constructor() {
for (index, item) in function.params.items.iter().enumerate() {
// transformed params will definitely have type annotation
let type_annotation =
self.ctx.ast.copy(&params.items[index].pattern.type_annotation);

if item.accessibility.is_some() {
let Some(ident_name) = item.pattern.get_identifier() else {
unreachable!()
};
let key = self.ctx.ast.property_key_identifier(
IdentifierName::new(SPAN, ident_name.clone()),
);
let new_elements = self.ctx.ast.class_property(
PropertyDefinitionType::PropertyDefinition,
item.span,
key,
None,
false,
false,
false,
item.r#override,
item.pattern.optional,
false,
item.readonly,
type_annotation,
self.transform_accessibility(item.accessibility),
self.ctx.ast.new_vec(),
);
elements.push(new_elements);
}
}
}

let type_annotation = self.infer_function_return_type(function);

let value = self.ctx.ast.function(
FunctionType::TSEmptyBodyFunctionExpression,
function.span,
self.ctx.ast.copy(&function.id),
function.generator,
function.r#async,
self.ctx.ast.copy(&function.this_param),
params,
None,
self.ctx.ast.copy(&function.type_parameters),
type_annotation,
Modifiers::empty(),
);
let new_element = self.ctx.ast.class_method(
definition.r#type,
definition.span,
self.ctx.ast.copy(&definition.key),
definition.kind,
value,
definition.computed,
definition.r#static,
definition.r#override,
definition.optional,
self.transform_accessibility(definition.accessibility),
self.ctx.ast.new_vec(),
);
elements.push(new_element);
}
ClassElement::PropertyDefinition(property) => {
if self.report_property_key(&property.key, property.computed) {
return None;
}

if property.key.is_private_identifier() {
has_private_key = true;
}
let type_annotations = property
.type_annotation
.as_ref()
.map(|type_annotation| self.ctx.ast.copy(type_annotation))
.or_else(|| {
let new_type = property
.value
.as_ref()
.and_then(|expr| self.infer_type_from_expression(expr))
.unwrap_or_else(|| {
// report error for has no type annotation
self.ctx.ast.ts_unknown_keyword(property.span)
});

Some(self.ctx.ast.ts_type_annotation(SPAN, new_type))
});

let new_element = self.ctx.ast.class_property(
property.r#type,
property.span,
self.ctx.ast.copy(&property.key),
None,
property.computed,
property.r#static,
property.declare,
property.r#override,
property.optional,
property.definite,
property.readonly,
type_annotations,
self.transform_accessibility(property.accessibility),
self.ctx.ast.new_vec(),
);
elements.push(new_element);
}
ClassElement::AccessorProperty(property) => {
if self.report_property_key(&property.key, property.computed) {
return None;
}

if property.key.is_private_identifier() {
has_private_key = true;
}
// FIXME: missing many fields
let new_element = self.ctx.ast.accessor_property(
property.r#type,
property.span,
self.ctx.ast.copy(&property.key),
None,
property.computed,
property.r#static,
self.ctx.ast.new_vec(),
);
elements.push(new_element);
}
ClassElement::TSIndexSignature(_) => elements.push(self.ctx.ast.copy(element)),
}
}

if has_private_key {
// <https://github.com/microsoft/TypeScript/blob/64d2eeea7b9c7f1a79edf42cb99f302535136a2e/src/compiler/transformers/declarations.ts#L1699-L1709>
// When the class has at least one private identifier, create a unique constant identifier to retain the nominal typing behavior
// Prevents other classes with the same public members from being used in place of the current class
let ident = self
.ctx
.ast
.property_key_private_identifier(PrivateIdentifier::new(SPAN, "private".into()));
let r#type = PropertyDefinitionType::PropertyDefinition;
let decorators = self.ctx.ast.new_vec();
let new_element = self.ctx.ast.class_property(
r#type, SPAN, ident, None, false, false, false, false, false, false, false, None,
None, decorators,
);
elements.insert(0, new_element);
}

let body = self.ctx.ast.class_body(decl.body.span, elements);

let modifiers = if decl.modifiers.is_contains_abstract() {
let modifiers = self.ctx.ast.new_vec_from_iter([
Modifier { span: SPAN, kind: ModifierKind::Declare },
Modifier { span: SPAN, kind: ModifierKind::Abstract },
]);
Modifiers::new(modifiers)
} else {
self.modifiers_declare()
};

Some(self.ctx.ast.class(
decl.r#type,
decl.span,
self.ctx.ast.copy(&decl.id),
self.ctx.ast.copy(&decl.super_class),
body,
self.ctx.ast.copy(&decl.type_parameters),
self.ctx.ast.copy(&decl.super_type_parameters),
self.ctx.ast.copy(&decl.implements),
self.ctx.ast.new_vec(),
modifiers,
))
}
}
Loading

0 comments on commit 909ab4d

Please sign in to comment.