Skip to content

Commit

Permalink
feat(isolated_declarations): add stripInternal (#5878)
Browse files Browse the repository at this point in the history
closes #3906
closes #5687
closes #3958

---------

Co-authored-by: Dunqing <dengqing0821@gmail.com>
  • Loading branch information
Boshen and Dunqing committed Sep 19, 2024
1 parent a07f03a commit 84a5816
Show file tree
Hide file tree
Showing 15 changed files with 281 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{env, path::Path};

use oxc_allocator::Allocator;
use oxc_codegen::{CodeGenerator, CommentOptions};
use oxc_isolated_declarations::IsolatedDeclarations;
use oxc_isolated_declarations::{IsolatedDeclarations, IsolatedDeclarationsOptions};
use oxc_parser::Parser;
use oxc_span::SourceType;

Expand Down Expand Up @@ -32,7 +32,13 @@ fn main() {
println!("Original:\n");
println!("{source_text}\n");

let id_ret = IsolatedDeclarations::new(&allocator).build(&ret.program);
let id_ret = IsolatedDeclarations::new(
&allocator,
&source_text,
&ret.trivias,
IsolatedDeclarationsOptions { strip_internal: true },
)
.build(&ret.program);
let printed = CodeGenerator::new()
.enable_comment(
&source_text,
Expand Down
17 changes: 16 additions & 1 deletion crates/oxc_isolated_declarations/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,10 @@ impl<'a> IsolatedDeclarations<'a> {
match element {
ClassElement::StaticBlock(_) => {}
ClassElement::MethodDefinition(ref method) => {
if self.has_internal_annotation(method.span) {
continue;
}

if !(method.r#type.is_abstract() || method.optional)
&& method.value.body.is_none()
{
Expand Down Expand Up @@ -439,6 +443,10 @@ impl<'a> IsolatedDeclarations<'a> {
elements.push(new_element);
}
ClassElement::PropertyDefinition(property) => {
if self.has_internal_annotation(property.span) {
continue;
}

if self.report_property_key(&property.key, property.computed) {
continue;
}
Expand All @@ -450,6 +458,10 @@ impl<'a> IsolatedDeclarations<'a> {
}
}
ClassElement::AccessorProperty(property) => {
if self.has_internal_annotation(property.span) {
continue;
}

if self.report_property_key(&property.key, property.computed) {
return None;
}
Expand All @@ -476,7 +488,10 @@ impl<'a> IsolatedDeclarations<'a> {
);
elements.push(new_element);
}
ClassElement::TSIndexSignature(_) => elements.push({
ClassElement::TSIndexSignature(signature) => elements.push({
if self.has_internal_annotation(signature.span) {
continue;
}
// SAFETY: `ast.copy` is unsound! We need to fix.
unsafe { self.ast.copy(element) }
}),
Expand Down
76 changes: 72 additions & 4 deletions crates/oxc_isolated_declarations/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,56 @@ use std::{cell::RefCell, collections::VecDeque, mem};
use diagnostics::function_with_assigning_properties;
use oxc_allocator::Allocator;
#[allow(clippy::wildcard_imports)]
use oxc_ast::{ast::*, AstBuilder, Visit, NONE};
use oxc_ast::{ast::*, AstBuilder, Trivias, Visit, NONE};
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{Atom, SourceType, SPAN};
use oxc_span::{Atom, GetSpan, SourceType, SPAN};
use rustc_hash::{FxHashMap, FxHashSet};

use crate::scope::ScopeTree;

#[derive(Debug, Clone, Copy)]
pub struct IsolatedDeclarationsOptions {
/// Do not emit declarations for code that has an @internal annotation in its JSDoc comment.
/// This is an internal compiler option; use at your own risk, because the compiler does not check that the result is valid.
/// <https://www.typescriptlang.org/tsconfig/#stripInternal>
pub strip_internal: bool,
}

pub struct IsolatedDeclarationsReturn<'a> {
pub program: Program<'a>,
pub errors: Vec<OxcDiagnostic>,
}

pub struct IsolatedDeclarations<'a> {
ast: AstBuilder<'a>,

// state
scope: ScopeTree<'a>,
errors: RefCell<Vec<OxcDiagnostic>>,

// options
strip_internal: bool,

/// Start position of `@internal` jsdoc annotations.
internal_annotations: FxHashSet<u32>,
}

impl<'a> IsolatedDeclarations<'a> {
pub fn new(allocator: &'a Allocator) -> Self {
pub fn new(
allocator: &'a Allocator,
source_text: &str,
trivias: &Trivias,
options: IsolatedDeclarationsOptions,
) -> Self {
let strip_internal = options.strip_internal;
let is_internal_set = strip_internal
.then(|| Self::build_internal_annotations(source_text, trivias))
.unwrap_or_default();

Self {
ast: AstBuilder::new(allocator),
strip_internal,
internal_annotations: is_internal_set,
scope: ScopeTree::new(allocator),
errors: RefCell::new(vec![]),
}
Expand All @@ -71,6 +98,27 @@ impl<'a> IsolatedDeclarations<'a> {
fn error(&self, error: OxcDiagnostic) {
self.errors.borrow_mut().push(error);
}

/// Build the lookup table for jsdoc `@internal`.
fn build_internal_annotations(source_text: &str, trivias: &Trivias) -> FxHashSet<u32> {
let mut set = FxHashSet::default();
for comment in trivias.comments() {
let has_internal = comment.span.source_text(source_text).contains("@internal");
// Use the first jsdoc comment if there are multiple jsdoc comments for the same node.
if has_internal && !set.contains(&comment.attached_to) {
set.insert(comment.attached_to);
}
}
set
}

/// Check if the node has an `@internal` annotation.
fn has_internal_annotation(&self, span: Span) -> bool {
if !self.strip_internal {
return false;
}
self.internal_annotations.contains(&span.start)
}
}

impl<'a> IsolatedDeclarations<'a> {
Expand Down Expand Up @@ -104,6 +152,9 @@ impl<'a> IsolatedDeclarations<'a> {
for stmt in Self::remove_function_overloads_implementation(unsafe { self.ast.copy(stmts) })
{
if let Some(decl) = stmt.as_declaration() {
if self.has_internal_annotation(decl.span()) {
continue;
}
if let Some(decl) = self.transform_declaration(decl, false) {
new_ast_stmts.push(Statement::from(decl));
} else {
Expand Down Expand Up @@ -138,6 +189,9 @@ impl<'a> IsolatedDeclarations<'a> {
match_declaration!(Statement) => {
match stmt.to_declaration() {
Declaration::VariableDeclaration(decl) => {
if self.has_internal_annotation(decl.span) {
continue;
}
variables_declarations.push_back(
// SAFETY: `ast.copy` is unsound! We need to fix.
unsafe { self.ast.copy(&decl.declarations) }
Expand All @@ -147,6 +201,9 @@ impl<'a> IsolatedDeclarations<'a> {
variable_transformed_indexes.push_back(FxHashSet::default());
}
Declaration::TSModuleDeclaration(decl) => {
if self.has_internal_annotation(decl.span) {
continue;
}
// declare global { ... } or declare module "foo" { ... }
// We need to emit it anyway
if decl.kind.is_global() || decl.id.is_string_literal() {
Expand All @@ -157,11 +214,16 @@ impl<'a> IsolatedDeclarations<'a> {
}
_ => {}
}
new_stmts.push(stmt);
if !self.has_internal_annotation(stmt.span()) {
new_stmts.push(stmt);
}
}
match_module_declaration!(Statement) => {
match stmt.to_module_declaration() {
ModuleDeclaration::ExportDefaultDeclaration(decl) => {
if self.has_internal_annotation(decl.span) {
continue;
}
transformed_indexes.insert(new_stmts.len());
if let Some((var_decl, new_decl)) =
self.transform_export_default_declaration(decl)
Expand All @@ -187,6 +249,9 @@ impl<'a> IsolatedDeclarations<'a> {
}

ModuleDeclaration::ExportNamedDeclaration(decl) => {
if self.has_internal_annotation(decl.span) {
continue;
}
transformed_indexes.insert(new_stmts.len());
if let Some(new_decl) = self.transform_export_named_declaration(decl) {
self.scope.visit_declaration(
Expand All @@ -205,6 +270,9 @@ impl<'a> IsolatedDeclarations<'a> {
// We must transform this in the end, because we need to know all references
}
module_declaration => {
if self.has_internal_annotation(module_declaration.span()) {
continue;
}
transformed_indexes.insert(new_stmts.len());
self.scope.visit_module_declaration(module_declaration);
}
Expand Down
4 changes: 4 additions & 0 deletions crates/oxc_isolated_declarations/src/signatures.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use oxc_allocator::{CloneIn, Vec};
use oxc_ast::ast::{TSMethodSignatureKind, TSSignature};
use oxc_span::GetSpan;
use rustc_hash::FxHashMap;

use crate::IsolatedDeclarations;
Expand All @@ -13,6 +14,9 @@ impl<'a> IsolatedDeclarations<'a> {
// <name, (requires_inference, first_param_annotation, return_type)>
let mut method_annotations: FxHashMap<_, (bool, _, _)> = FxHashMap::default();

// Strip internal signatures
signatures.retain(|signature| !self.has_internal_annotation(signature.span()));

signatures.iter_mut().for_each(|signature| {
if let TSSignature::TSMethodSignature(method) = signature {
let Some(name) = method.key.static_name() else {
Expand Down
14 changes: 9 additions & 5 deletions crates/oxc_isolated_declarations/tests/deno/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@
mod tests {
use oxc_allocator::Allocator;
use oxc_codegen::CodeGenerator;
use oxc_isolated_declarations::IsolatedDeclarations;
use oxc_isolated_declarations::{IsolatedDeclarations, IsolatedDeclarationsOptions};
use oxc_parser::Parser;
use oxc_span::SourceType;

fn transform_dts_test(source: &str, expected: &str) {
let allocator = Allocator::default();
let source_type = SourceType::from_path("test.ts").unwrap();
let program = Parser::new(&allocator, source, source_type).parse().program;

let ret = IsolatedDeclarations::new(&allocator).build(&program);
let ret = Parser::new(&allocator, source, source_type).parse();
let ret = IsolatedDeclarations::new(
&allocator,
source,
&ret.trivias,
IsolatedDeclarationsOptions { strip_internal: true },
)
.build(&ret.program);
let actual = CodeGenerator::new().build(&ret.program).source_text;
let expected_program = Parser::new(&allocator, expected, source_type).parse().program;
let expected = CodeGenerator::new().build(&expected_program).source_text;

assert_eq!(actual.trim(), expected.trim());
}

Expand Down
82 changes: 82 additions & 0 deletions crates/oxc_isolated_declarations/tests/fixtures/strip-internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
@internal
*/
class StripInternalClass {
public test() {
console.log("test");
}
}

class StripInternalClassFields {
/**
* @internal
*/
internalProperty: string = "internal";

// @internal
internalMethod(): void {}
}

/**
@internal
*/
function stripInternalFunction() {
console.log("test");
}

export { stripInternalFunction, StripInternalClass, StripInternalClassFields };

/**
@internal
*/
export function stripInternalExportedFunction() {
console.log("test");
}

/**
@internal*/
export const stripInternalExportedConst = "test";

/**
@internal*/
export interface StripInternalExportedInterface {}

export interface StripInternalInterfaceSignatures {
/**
* @internal
*/
internalMethod(): void;
/**
* @internal
*/
internalProperty: number;
/**@internal */
new (): any;
}

export type StripInternalTypeSignatures = {
/**
* @internal
*/
internalMethod(): void;
/**
* @internal
*/
internalProperty: number;
/**@internal */
new (): any;
};

export namespace StripInternalNamespaceInner {
/**
* @internal
*/
export function internalFunction() {
console.log("test");
}
}

/**
* @internal
*/
export namespace StripInternalNamespace {}
10 changes: 8 additions & 2 deletions crates/oxc_isolated_declarations/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{fs, path::Path, sync::Arc};

use oxc_allocator::Allocator;
use oxc_codegen::{CodeGenerator, CommentOptions};
use oxc_isolated_declarations::IsolatedDeclarations;
use oxc_isolated_declarations::{IsolatedDeclarations, IsolatedDeclarationsOptions};
use oxc_parser::Parser;
use oxc_span::SourceType;

Expand All @@ -13,7 +13,13 @@ fn transform(path: &Path, source_text: &str) -> String {
let source_type = SourceType::from_path(path).unwrap();
let parser_ret = Parser::new(&allocator, source_text, source_type).parse();

let id_ret = IsolatedDeclarations::new(&allocator).build(&parser_ret.program);
let id_ret = IsolatedDeclarations::new(
&allocator,
source_text,
&parser_ret.trivias,
IsolatedDeclarationsOptions { strip_internal: true },
)
.build(&parser_ret.program);
let code = CodeGenerator::new()
.enable_comment(
source_text,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
source: crates/oxc_isolated_declarations/tests/mod.rs
input_file: crates/oxc_isolated_declarations/tests/fixtures/strip-internal.ts
---
==================== .D.TS ====================

declare class StripInternalClassFields {}
export { stripInternalFunction, StripInternalClass, StripInternalClassFields };
export interface StripInternalInterfaceSignatures {}
export type StripInternalTypeSignatures = {};
export declare namespace StripInternalNamespaceInner {
export {};
}
Loading

0 comments on commit 84a5816

Please sign in to comment.