@ 261027.7
current
const { test, snapshot } = require("node:test");
const { transformSync } = require("../dist/index.js");
const path = require("node:path");
const assert = require("node:assert");
const vm = require("node:vm");

// Set the path for the snapshots directory
snapshot.setResolveSnapshotPath((testPath) => {
	return path.join(
		__dirname,
		"snapshots",
		`${path.basename(testPath)}.snapshot`,
	);
});

test("should perform type stripping", (t) => {
	const { code } = transformSync("const foo: string = 'bar';");
	t.assert.snapshot(code);
});

test("should strip type annotations from functions", (t) => {
	const inputCode = "function greet(name: string): void { console.log(name); }";
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});

test("should strip type annotations from classes", (t) => {
	const inputCode = `
    class MyClass {
      myMethod(param: number): string {
        return param.toString();
      }
    }
  `;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});

test("should strip type annotations from interfaces", (t) => {
	const inputCode = `
    interface MyInterface {
      myMethod(param: number): string;
    }
  `;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});

test("should strip type annotations from type aliases", (t) => {
	const inputCode = `
    type MyType = string | number;
  `;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});

test("should strip type annotations from generics", (t) => {
	const inputCode = `
    function identity<T>(arg: T): T {
      return arg;
    }
  `;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});

test("should strip type annotations from arrow functions", (t) => {
	const inputCode = `
    const greet = (name: string): void => {
      console.log(name);
    };
  `;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});

test("should strip type annotations from type assertions", (t) => {
	const inputCode = `
    let someValue: any = "this is a string";
    let strLength: number = (someValue as string).length;
  `;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});

test("should handle User type and isAdult function", (t) => {
	const inputCode = `
    type User = {
      name: string;
      age: number;
    };

    function isAdult(user: User): boolean {
      return user.age >= 18;
    }
  `;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});

test("should handle class modifiers", (t) => {
	const inputCode = `
		class PrivateConstructor {
		  private constructor() {}
		  public a() {}
		  protected b() {}
		  static create() {
		    return new PrivateConstructor()
		  }
		}

		const ins = PrivateConstructor.create()
		console.log(ins)
	`;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
	assert.strictEqual(code.includes("private"), false);
	assert.strictEqual(code.includes("protected"), false);
	assert.strictEqual(code.includes("public"), false);
});

test("should handle empty source code", (t) => {
	assert.strictEqual(transformSync().code, "");
	assert.throws(() => transformSync({}).code);
	assert.strictEqual(transformSync(false).code, "false");
	assert.strictEqual(transformSync(undefined).code, "");
	assert.strictEqual(transformSync(null).code, "");
	assert.strictEqual(transformSync("").code, "");
});

test("should not polyfill using Symbol.Dispose", (t) => {
	const inputCode = `
	class Resource {
		[Symbol.dispose]() { console.log("Disposed"); }
	}
	using r = new Resource();`;
	const { code } = transformSync(inputCode);
	assert.strictEqual(code, inputCode);
});

test("should not polyfill using Symbol.asyncDispose", (t) => {
	const inputCode = `
	class AsyncResource {
		async [Symbol.asyncDispose]() { console.log("Async disposed"); }
	}
	await using r = new AsyncResource();`;
	const { code } = transformSync(inputCode);
	assert.strictEqual(code, inputCode);
});

test("should not break on return new line when stripped", (t) => {
	const inputCode = `
	function mkId() {
		return <T>
			(x: T)=>x;
	}
	const id = mkId();
	output = id(5);`;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
	const result = vm.runInContext(code, vm.createContext());
	assert.strictEqual(result, 5);
});

test("should not break on return new line when stripped (alternative formatting)", (t) => {
	const inputCode = `
	function mkId() {
		return <
			T
		>(x: T)=>x;
	}
	const id = mkId();
	output = id(7);`;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
	const result = vm.runInContext(code, vm.createContext());
	assert.strictEqual(result, 7);
});

test("should not throw on return new line when stripped", (t) => {
	const inputCode = `
	function mkId() {
		throw <
			T
		>(x: T)=>x;
	}

	try {
		mkId();
	}
	catch(e){
		output = e(5);
	}`;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
	const result = vm.runInContext(code, vm.createContext());
	assert.strictEqual(result, 5);
});

test("should not throw on yield new line when stripped", (t) => {
	const inputCode = `
	function* mkId() {
		yield <
				T
		>(x: T)=>x;
	}
	output= mkId().next().value(5);`;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
	const result = vm.runInContext(code, vm.createContext());
	assert.strictEqual(result, 5);
});

test("should throw invalid syntax error", (t) => {
	assert.throws(() => transformSync("const foo;"));
});

test("erasable namespaces and modules should be supported", (t) => {
	const tests = [
		"namespace Empty {}",
		`namespace TypeOnly {
    		type A = string;

    		export type B = A | number;

   			export interface I {}

			export namespace Inner {
				export type C = B;
			}
		}`,
		`namespace My.Internal.Types {
    		export type Foo = number;
		}`,
		"declare namespace C { export let x = 1 }",
	];
	for (const input of tests) {
		const { code } = transformSync(input);
		t.assert.snapshot(code);
	}
});

test("should throw on non erasable namespace/module", (t) => {
	const tests = [
		"namespace A { export let x = 1 }",
		`namespace With.Imports {
    		import Types = My.Internal.Types;
    		export type Foo = Types.Foo;
		}`,
		"namespace B { ; } ",
		"module E { export let x = 1 }",
		`namespace A { export let x = 1; }
         namespace B { import x = A.x; }
         namespace C { export import x = A.x; }`,
		"declare module    D { export let x = 1 }",
		"module F { export type x = number }",
	];

	for (const input of tests) {
		assert.throws(() => transformSync(input), { code: "UnsupportedSyntax" });
	}
});

test("should perform type stripping on nested generics", (t) => {
	const { code } = transformSync(
		"const promiseWrapper = new Wrapper<<T>(x: T) => Promise<T>>(Promise.resolve.bind(Promise));",
	);
	t.assert.snapshot(code);
});

test("should handle deeply nested expressions", (t) => {
	const source = `var data = ""
if(!(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((data === "AED") || (data === "AFN")) || (data === "ALL")) || (data === "AMD")) || (data === "ANG")) || (data === "AOA")) || (data === "ARS")) || (data === "AUD")) || (data === "AWG")) || (data === "AZN")) || (data === "BAM")) || (data === "BBD")) || (data === "BDT")) || (data === "BGN")) || (data === "BHD")) || (data === "BIF")) || (data === "BMD")) || (data === "BND")) || (data === "BOB")) || (data === "BOV")) || (data === "BRL")) || (data === "BSD")) || (data === "BTN")) || (data === "BWP")) || (data === "BYN")) || (data === "BZD")) || (data === "CAD")) || (data === "CDF")) || (data === "CHE")) || (data === "CHF")) || (data === "CHW")) || (data === "CLF")) || (data === "CLP")) || (data === "CNY")) || (data === "COP")) || (data === "COU")) || (data === "CRC")) || (data === "CUC")) || (data === "CUP")) || (data === "CVE")) || (data === "CZK")) || (data === "DJF")) || (data === "DKK")) || (data === "DOP")) || (data === "DZD")) || (data === "EGP")) || (data === "ERN")) || (data === "ETB")) || (data === "EUR")) || (data === "FJD")) || (data === "FKP")) || (data === "GBP")) || (data === "GEL")) || (data === "GHS")) || (data === "GIP")) || (data === "GMD")) || (data === "GNF")) || (data === "GTQ")) || (data === "GYD")) || (data === "HKD")) || (data === "HNL")) || (data === "HRK")) || (data === "HTG")) || (data === "HUF")) || (data === "IDR")) || (data === "ILS")) || (data === "INR")) || (data === "IQD")) || (data === "IRR")) || (data === "ISK")) || (data === "JMD")) || (data === "JOD")) || (data === "JPY")) || (data === "KES")) || (data === "KGS")) || (data === "KHR")) || (data === "KMF")) || (data === "KPW")) || (data === "KRW")) || (data === "KWD")) || (data === "KYD")) || (data === "KZT")) || (data === "LAK")) || (data === "LBP")) || (data === "LKR")) || (data === "LRD")) || (data === "LSL")) || (data === "LYD")) || (data === "MAD")) || (data === "MDL")) || (data === "MGA")) || (data === "MKD")) || (data === "MMK")) || (data === "MNT")) || (data === "MOP")) || (data === "MRU")) || (data === "MUR")) || (data === "MVR")) || (data === "MWK")) || (data === "MXN")) || (data === "MXV")) || (data === "MYR")) || (data === "MZN")) || (data === "NAD")) || (data === "NGN")) || (data === "NIO")) || (data === "NOK")) || (data === "NPR")) || (data === "NZD")) || (data === "OMR")) || (data === "PAB")) || (data === "PEN")) || (data === "PGK")) || (data === "PHP")) || (data === "PKR")) || (data === "PLN")) || (data === "PYG")) || (data === "QAR")) || (data === "RON")) || (data === "RSD")) || (data === "RUB")) || (data === "RWF")) || (data === "SAR")) || (data === "SBD")) || (data === "SCR")) || (data === "SDG")) || (data === "SEK")) || (data === "SGD")) || (data === "SHP")) || (data === "SLL")) || (data === "SOS")) || (data === "SRD")) || (data === "SSP")) || (data === "STN")) || (data === "SVC")) || (data === "SYP")) || (data === "SZL")) || (data === "THB")) || (data === "TJS")) || (data === "TMT")) || (data === "TND")) || (data === "TOP")) || (data === "TRY")) || (data === "TTD")) || (data === "TWD")) || (data === "TZS")) || (data === "UAH")) || (data === "UGX")) || (data === "USD")) || (data === "USN")) || (data === "UYI")) || (data === "UYU")) || (data === "UYW")) || (data === "UZS")) || (data === "VES")) || (data === "VND")) || (data === "VUV")) || (data === "WST")) || (data === "XAF")) || (data === "XAG")) || (data === "XAU")) || (data === "XBA")) || (data === "XBB")) || (data === "XBC")) || (data === "XBD")) || (data === "XCD")) || (data === "XDR")) || (data === "XOF")) || (data === "XPD")) || (data === "XPF")) || (data === "XPT")) || (data === "XSU")) || (data === "XTS")) || (data === "XUA")) || (data === "XXX")) || (data === "YER")) || (data === "ZAR")) || (data === "ZMW")) || (data === "ZWL"))) {
  console.log("Hello");
}`;
	assert.doesNotThrow(() => transformSync(source));
});

test("should handle advanced type-level constructs", (t) => {
	const inputCode = `
		type Fn = (x: string) => number;

		type ReturnType<T> = T extends (...args: any) => infer R ? R : never;

		type X = ReturnType<Fn>;

		type Props = { id: string; name: string };
		type Keys = keyof Props;

		type A = typeof Math;
	`;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});

test("should strip 'satisfies' expressions", (t) => {
	const inputCode = `
		const user = {
			name: "Alice",
			age: 30,
		} satisfies { name: string, age: number };
	`;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});

test("should preserve import/export type declarations", (t) => {
	const inputCode = `
		import type { SomeType } from "./types";
		export type { SomeType };
	`;
	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});

test("should strip correctly private properties overload", (t) => {
	const inputCode = `class Private {
		#foo(bar: string): string;
		#foo(bar: number): number;
		#foo(bar: string | number): string | number;
		#foo(bar: string | number): string | number {
			return bar;
		}
	}`;

	const { code } = transformSync(inputCode);
	t.assert.snapshot(code);
});