import { List, namekey, Output, refkey, render, StatementList, } from "@alloy-js/core"; import { describe, expect, it } from "vitest"; import * as ts from "../src/components/index.js"; import { TestFile } from "./utils.js"; it("declares classes", () => { const res = ( ); expect(res).toRenderTo(` class Foo {} `); }); it("accepts export and default", () => { const res = ( ); expect(res).toRenderTo(` export default class Foo {} `); }); it("creates extends", () => { const res = ( ); expect(res).toRenderTo(` class Foo extends string {} `); }); it("creates implements", () => { const res = ( ); expect(res).toRenderTo(` class Foo implements SomeInterface {} `); }); it("creates implements with multiple", () => { const res = ( ); expect(res).toRenderTo(` class Foo implements SomeInterface, OtherInterface {} `); }); it("creates implements with extends", () => { const res = ( ); expect(res).toRenderTo(` class Foo extends string implements SomeInterface {} `); }); it("takes namekeys for all elements", () => { const res = ( ); expect(res).toRenderTo(` class foo { myField; myMethod() {}; } `); }); describe("instance members", () => { it("can be created", () => { const res = ( 12 ); expect(res).toRenderTo(` class Foo { one; public two; private three; protected four; five: number; six: number = 12; #seven; } `); }); it("can be referenced", () => { const one = refkey(); const privateOne = refkey(); const res = ( 1 {one} + 1 1 {privateOne} + 1 ); expect(res).toRenderTo(` class Foo { one = 1; two = this.one + 1; #one = 1; three = this.#one + 1; } `); }); it("cannot be referenced outside the class", () => { const one = refkey(); expect(() => { render( 1 {one} , { insertFinalNewLine: false }, ); }).toThrow( /Cannot reference instance member 'one' without an instance of 'Foo'/, ); }); it("cannot be referenced outside the class when protected", () => { const one = refkey(); expect(() => { render( 1 {one} , { insertFinalNewLine: false }, ); }).toThrow( /Cannot reference instance member 'one' without an instance of 'Foo'/, ); }); it("cannot be referenced outside the class when private", () => { const one = refkey(); expect(() => { render( 1 {one} , { insertFinalNewLine: false }, ); }).toThrow( /Cannot reference instance member 'one' without an instance of 'Foo'/, ); }); it("works with invalid identifier names", () => { const one = refkey(); const res = ( 1 {one} + 1 ); expect(res).toRenderTo(` class Foo { "o-n-e" = 1; "t-w-o" = this["o-n-e"] + 1; } `); }); it("doesn't conflict with variables outside the class", () => { const rk = refkey(); const res = ( 1; 2; 1 {rk} + 1 ); expect(res).toRenderTo(` const one = 1; const two = 2; class Foo { one = 1; two() { this.one + 1 }; } `); }); it("doesn't conflict with imports from other files", () => { const rk1 = refkey(); const rk2 = refkey(); expect( { // do nothing return undefined; }} > 1 2 {rk1} {rk2} , ).toRenderTo({ "decl.ts": ` export const one = 1; export const two = 2; `, "ref.ts": ` import { one, two } from "./decl.js"; class Foo { one = one; two() { two }; } `, }); }); }); describe("static members", () => { it("renders", () => { const one = refkey(); const res = ( 1 2 ); expect(res).toRenderTo(` class Foo { static one = 1; static #two = 2; } `); }); it("can be referenced", () => { const one = refkey(); const two = refkey(); const res = ( 1 2 return {two}; {one}; ); expect(res).toRenderTo(` class Foo { static one = 1; static #two = 2; getTwo() { return Foo.#two; }; } Foo.one; `); }); it("cannot be referenced outside the class when private", () => { const two = refkey(); expect(() => render( 2 {two}; , { insertFinalNewLine: false }, ), ).toThrow(/Cannot reference/); }); }); describe("instance methods", () => { it("renders", () => { const one = refkey(); const a = refkey(); const b = refkey(); const res = ( {one} = {a} + {b}; ); expect(res).toRenderTo(` class Foo { one() {} public two() {} private three() {} protected four() {} five(a: string, b: string) {} six(a: number, b: number): number { this.one = a + b; } #seven() {} } `); }); }); it("renders a class with docs for the class and its members", () => { const res = ( 123 ; return 123; ); expect(res).toRenderTo(` /** * This is a class documentation */ class Foo { /** * This is a field documentation */ bar = 123; /** * This is a method documentation */ baz() { return 123; } } `); }); it("renders a method with parameter docs", () => { const res = ( ); expect(res).toRenderTo( ` class Foo { /** * Method documentation * * @param {number} a - Parameter a doc * @param {string} b - Line 1 for b. * This is a long description that * should continue in the next line. */ bar(a: number, b: string): void {} } `, { printWidth: 40 }, ); });