diff --git a/crates/oxc_isolated_declarations/tests/deno.rs b/crates/oxc_isolated_declarations/tests/deno.rs new file mode 100644 index 0000000000000..ff5f692528836 --- /dev/null +++ b/crates/oxc_isolated_declarations/tests/deno.rs @@ -0,0 +1,397 @@ +//! Copy from +//! Make some changes to conform to the Isolated Declarations output + +#[cfg(test)] +mod tests { + use oxc_allocator::Allocator; + use oxc_codegen::CodeGenerator; + use oxc_isolated_declarations::IsolatedDeclarations; + 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 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()); + } + + #[test] + fn dts_function_test() { + transform_dts_test( + "export function foo(a: number): number { + return {}; +}", + "export declare function foo(a: number): number;", + ); + transform_dts_test( + "export function foo(a: string): number; +export function foo(a: any): number { + return {}; +}", + "export declare function foo(a: string): number;", + ); + transform_dts_test( + "export function foo(a = 2): number { + return 2; +}", + "export declare function foo(a?: number): number;", + ); + transform_dts_test( + "export function foo(a: string = 2): number { + return 2; +}", + "export declare function foo(a?: string): number;", + ); + // TODO: Isolated Declarations doesn't ObjectPattern + // transform_dts_test( + // "export function foo({a, b} = { a: 1, b: 2 }): number { + // return 2; + // }", + // "export declare function foo({ a, b }?: { + // a: number; + // b: number; + // }): number;", + // ); + } + + #[test] + fn dts_class_decl_test() { + transform_dts_test( + "export class Foo { + a: number = 2; + static b: number = 1; + #b: number = 3; + constructor(value: string) { + return 42; + } + foo(): string { + return \"abc\"; + } + #bar(): number { + return 2 + } + get asdf(): number { + + } + set asdf(value: number) { + + } + + static { + + } +}", + "export declare class Foo { + #private; + a: number; + static b: number; + constructor(value: string); + foo(): string; + get asdf(): number; + set asdf(value: number); +}", + ); + } + + #[test] + fn dts_class_decl_rest_test() { + transform_dts_test( + "export class Foo { + constructor(...args: string[]) {} +}", + "export declare class Foo { + constructor(...args: string[]); +}", + ); + } + + #[test] + #[ignore = "Doesn't support class function overloads"] + fn dts_class_decl_overloads_test() { + transform_dts_test( + "export class Foo { + constructor(arg: string); + constructor(arg: number); + constructor(arg: any) {} +}", + "export declare class Foo { + constructor(arg: string); + constructor(arg: number); +}", + ); + + transform_dts_test( + "export class Foo { + foo(arg: string); + foo(arg: number); + foo(arg: any) {} +}", + "export declare class Foo { + foo(arg: string); + foo(arg: number); +}", + ); + + transform_dts_test( + "export class Foo { + constructor(arg: string); + constructor(arg: number); + constructor(arg: any) {} + + bar(arg: number): number { + return 2 + } + + foo(arg: string); + foo(arg: number); + foo(arg: any) {} +}", + "export declare class Foo { + constructor(arg: string); + constructor(arg: number); + bar(arg: number): number; + foo(arg: string); + foo(arg: number); +}", + ); + } + + #[test] + fn dts_class_decl_prop_test() { + transform_dts_test( + "export class Foo { declare a: string }", + "export declare class Foo { + a: string; +}", + ); + } + + #[test] + fn dts_class_decl_prop_infer_test() { + transform_dts_test( + "export class Foo { foo = (a: string): string => ({} as any) }", + "export declare class Foo { + foo: (a: string) => string; +}", + ); + transform_dts_test( + "export class Foo { foo = function(a: string): void {} }", + "export declare class Foo { + foo: (a: string) => void; +}", + ); + } + + #[test] + fn dts_var_decl_test() { + transform_dts_test("export const foo: number = 42;", "export declare const foo: number;"); + + transform_dts_test("export var foo: number = 42;", "export declare var foo: number;"); + + transform_dts_test("export let foo: number = 42;", "export declare let foo: number;"); + } + + #[test] + fn dts_global_declare() { + transform_dts_test( + "declare global { + interface String { + fancyFormat(opts: StringFormatOptions): string; + } +}", + "declare global { + interface String { + fancyFormat(opts: StringFormatOptions): string; + } +}", + ); + } + + #[test] + fn dts_inference() { + transform_dts_test( + "export const foo = null as string as number;", + "export declare const foo: number;", + ); + } + + #[test] + fn dts_as_const() { + transform_dts_test( + "export const foo = [1, 2] as const;", + "export declare const foo: readonly [1, 2];", + ); + transform_dts_test( + "export const foo = [1, ,2] as const;", + "export declare const foo: readonly [1, undefined, 2];", + ); + + transform_dts_test( + "export const foo = { str: \"bar\", bool: true, bool2: false, num: 42, nullish: null } as const;", + "export declare const foo: { + readonly str: \"bar\"; + readonly bool: true; + readonly bool2: false; + readonly num: 42; + readonly nullish: null; +};", + ); + + transform_dts_test( + "export const foo = { str: [1, 2] as const } as const;", + "export declare const foo: { + readonly str: readonly [1, 2]; +};", + ); + } + + #[test] + fn dts_literal_inference_ann() { + transform_dts_test( + "export const foo: number = \"abc\";", + "export declare const foo: number;", + ); + transform_dts_test("export let foo: number = \"abc\";", "export declare let foo: number;"); + transform_dts_test("export var foo: number = \"abc\";", "export declare var foo: number;"); + } + + #[test] + fn dts_literal_inference() { + transform_dts_test("export const foo = 42;", "export declare const foo = 42;"); + transform_dts_test("export const foo = \"foo\";", "export declare const foo = \"foo\";"); + transform_dts_test("export const foo = true;", "export declare const foo: boolean;"); + transform_dts_test("export const foo = false;", "export declare const foo: boolean;"); + transform_dts_test("export const foo = null;", "export declare const foo: null;"); + transform_dts_test("export let foo = undefined;", "export declare let foo: undefined;"); + transform_dts_test("export let foo = 10n;", "export declare let foo: bigint;"); + } + + #[test] + fn dts_fn_expr() { + transform_dts_test( + "export let foo = function add(a: number, b: number): number { + return a + b; +}", + "export declare let foo: (a: number, b: number) => number;", + ); + transform_dts_test( + "export let foo = function add([a, b]: T): void {}", + "export declare let foo: ([a, b]: T) => void;", + ); + transform_dts_test( + "export let foo = function add({a, b}: T): void {}", + "export declare let foo: ({ a, b }: T) => void;", + ); + transform_dts_test( + "export let foo = function add(a = 2): void {}", + "export declare let foo: (a?: number) => void;", + ); + transform_dts_test( + "export let foo = function add(...params: any[]): void {}", + "export declare let foo: (...params: any[]) => void;", + ); + } + + #[test] + fn dts_fn_arrow_expr() { + transform_dts_test( + "export let foo = (a: number, b: number): number => { + return a + b; +}", + "export declare let foo: (a: number, b: number) => number;", + ); + transform_dts_test( + "export let foo = ([a, b]: T): void => {}", + "export declare let foo: ([a, b]: T) => void;", + ); + transform_dts_test( + "export let foo = ({a, b}: T): void => {}", + "export declare let foo: ({ a, b }: T) => void;", + ); + transform_dts_test( + "export let foo = (a = 2): void => {}", + "export declare let foo: (a?: number) => void;", + ); + + transform_dts_test( + "export let foo = (...params: any[]): void => {}", + "export declare let foo: (...params: any[]) => void;", + ); + } + + #[test] + fn dts_type_export() { + transform_dts_test("interface Foo {}", "interface Foo {\n}"); + transform_dts_test("type Foo = number;", "type Foo = number;"); + + transform_dts_test("export interface Foo {}", "export interface Foo {\n}"); + transform_dts_test("export type Foo = number;", "export type Foo = number;"); + } + + #[test] + fn dts_enum_export() { + transform_dts_test( + "export enum Foo { A, B }", + "export declare enum Foo {\n A=0,\n B=1\n}", + ); + transform_dts_test( + "export const enum Foo { A, B }", + "export declare const enum Foo {\n A=0,\n B=1\n}", + ); + + transform_dts_test( + "export enum Foo { A = \"foo\", B = \"bar\" }", + "export declare enum Foo {\n A = \"foo\",\n B = \"bar\"\n}", + ); + + // TODO: Enum rules https://www.typescriptlang.org/docs/handbook/enums.html + } + + #[test] + fn dts_default_export() { + transform_dts_test( + "export default function(a: number, b: number): number {};", + "export default function(a: number, b: number): number;", + ); + // TODO export default function overloads + // transform_dts_test( + // "export default function(a: number, b: number): number; + // export default function(a: number, b: number): any { + // return foo + // };", + // "export default function(a: number, b: number): number;", + // ); + transform_dts_test( + "export default class {foo = 2};", + "export default class {\n foo: number;\n}", + ); + transform_dts_test( + "export default 42;", + "declare const _default: number;\nexport default _default;", + ); + transform_dts_test( + "const a: number = 42; export default a;", + "declare const a: number;\nexport default a;", + ); + } + + #[test] + fn dts_default_export_named() { + transform_dts_test( + "export { foo, bar } from \"foo\";", + "export { foo, bar } from \"foo\";", + ); + } + + #[test] + fn dts_default_export_all() { + transform_dts_test("export * as foo from \"foo\";", "export * as foo from \"foo\";"); + } +} diff --git a/crates/oxc_isolated_declarations/tests/mod.rs b/crates/oxc_isolated_declarations/tests/mod.rs index bf039e8120f5c..56ceacfe4a11a 100644 --- a/crates/oxc_isolated_declarations/tests/mod.rs +++ b/crates/oxc_isolated_declarations/tests/mod.rs @@ -1,3 +1,5 @@ +mod deno; + use std::{fs, path::Path, sync::Arc}; use oxc_allocator::Allocator;