Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .chronus/changes/block-closer-2025-8-4-19-4-17.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: feature
packages:
- "@alloy-js/core"
---

The `<Block>` component no longer emits an empty line when the `closer` prop is `false.
7 changes: 7 additions & 0 deletions .chronus/changes/block-closer-2025-8-4-19-6-12.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: feature
packages:
- "@alloy-js/python"
---

The `<PythonBlock>` component no longer emits an empty line after it. Use an explicit `<hbr />` or `<List doubleHardline>` to recover the old formatting.
7 changes: 4 additions & 3 deletions packages/core/src/components/Block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ export interface BlockProps {
opener?: string;

/**
* The closing punctuation of the block. Defaults to "\}".
* The closing punctuation of the block. Defaults to "\}". When passed `false`,
* no closing punctuation will be added and there will be no trailing newline.
*/
closer?: string;
closer?: string | boolean;

/**
* Whether the block starts on a new line. When true, a hardline is added
Expand Down Expand Up @@ -41,7 +42,7 @@ export function Block(props: BlockProps) {
<Indent
line={props.inline && childCount.value > 0}
softline={childCount.value === 0}
trailingBreak
trailingBreak={props.closer !== false}
>
{props.children}
</Indent>
Expand Down
31 changes: 31 additions & 0 deletions packages/core/test/components/block.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,34 @@ it("renders properly with newline and no children", () => {
}
`);
});

it("takes a custom closer and opener", () => {
const template = (
<>
<Block opener="[" closer="]">
Contents!!!
</Block>
following content
</>
);
expect(template).toRenderTo(`
[
Contents!!!
]following content
`);
});

it("takes a false closer", () => {
const template = (
<>
<Block opener="(" closer={false}>
Contents!!!
</Block>
following content
</>
);
expect(template).toRenderTo(`
(
Contents!!!following content
`);
});
2 changes: 1 addition & 1 deletion packages/python/src/components/PythonBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export interface PythonBlockProps {
*/
export function PythonBlock(props: PythonBlockProps) {
return (
<Block opener={props.opener ?? ""} closer="">
<Block opener={props.opener ?? ""} closer={false}>
{props.children}
</Block>
);
Expand Down
5 changes: 1 addition & 4 deletions packages/python/src/components/SourceFile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
ComponentContext,
SourceFile as CoreSourceFile,
createNamedContext,
List,
Scope,
Show,
SourceDirectoryContext,
Expand Down Expand Up @@ -84,9 +83,7 @@ export function SourceFile(props: SourceFileProps) {
<hbr />
</Show>
<PythonSourceFileContext.Provider value={sfContext}>
<Scope value={scope}>
<List doubleHardline>{props.children}</List>
</Scope>
<Scope value={scope}>{props.children}</Scope>
</PythonSourceFileContext.Provider>
</CoreSourceFile>
);
Expand Down
34 changes: 1 addition & 33 deletions packages/python/test/classdeclarations.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ describe("Python Class", () => {
expect(result).toRenderTo(d`
class Foo:
pass


`);
});

Expand All @@ -26,8 +24,6 @@ describe("Python Class", () => {
expect(result).toRenderTo(d`
class Foo:
pass


`);
});

Expand All @@ -38,8 +34,6 @@ describe("Python Class", () => {
expect(result).toRenderTo(d`
class Bar:
print('hi')


`);
});

Expand All @@ -57,14 +51,10 @@ describe("Python Class", () => {
const expected = d`
class Base1:
pass

class Base2:
pass

class Baz(Base1, Base2):
pass


`;
expect(result).toRenderTo(expected);
});
Expand All @@ -75,11 +65,9 @@ describe("Python Class", () => {
print('hello')
</py.ClassDeclaration>,
]);
expect(result).toRenderTo(d`
expect(result).toRenderTo(`
class Qux(Base):
print('hello')


`);
});

Expand All @@ -102,24 +90,18 @@ describe("Python Class", () => {
const mod1Expected = d`
class A:
pass


`;
const mod2Expected = d`
from mod1 import A

class B(A):
pass


`;
const mod3Expected = d`
from folder.mod2 import B

class C(B):
pass


`;
assertFileContents(result, { "mod1.py": mod1Expected });
assertFileContents(result, { "folder/mod2.py": mod2Expected });
Expand All @@ -141,12 +123,9 @@ describe("Python Class", () => {
const expected = d`
class A:
pass

class B:
bar: A
foo: str


`;
expect(result).toRenderTo(expected);
});
Expand Down Expand Up @@ -184,10 +163,8 @@ describe("Python Class", () => {
const expected = d`
class A:
foo: str

class B:
foo: str

A.foo
B.foo
`;
Expand Down Expand Up @@ -229,14 +206,11 @@ describe("Python Class - VariableDeclaration", () => {
const expected = d`
class Base:
pass

class A:
just_name = None
name_and_type: number = None
name_type_and_value: number = 12
class_based: Base = None


`;
expect(result).toRenderTo(expected);
});
Expand Down Expand Up @@ -293,8 +267,6 @@ describe("Python Class - VariableDeclaration", () => {
instance_prop = 42
def instance_method(self) -> int:
pass


`,
});
});
Expand Down Expand Up @@ -351,14 +323,10 @@ describe("Python Class - FunctionDeclaration", () => {
b: int = None
def my_method(self, a: int, b: int) -> int:
return a + b

def my_class_method(cls) -> int:
pass

def my_standalone_function() -> int:
pass


MyClass.my_class_method
MyClass.my_standalone_function
`;
Expand Down
7 changes: 2 additions & 5 deletions packages/python/test/classinstantiations.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ it("declaration of class instance with variables", () => {
const expected = d`
class OneClass:
pass

OneClass("A name", 42, True)
`;
expect(result).toRenderTo(expected);
Expand Down Expand Up @@ -147,11 +146,9 @@ it("incorrect Class instantiation works", () => {
const expected = d`
MyClass(
class NestedClass:
pass
,
pass,
def my_func():
pass
,
pass,
x = None
)
`;
Expand Down
12 changes: 0 additions & 12 deletions packages/python/test/enums.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ describe("Python Enum", () => {
RED = 1
GREEN = 2
BLUE = 3


`;
expect(result).toRenderTo(expected);
});
Expand All @@ -56,8 +54,6 @@ describe("Python Enum", () => {
RED = "1"
GREEN = 2
BLUE = "3"


`;
expect(result).toRenderTo(expected);
});
Expand Down Expand Up @@ -85,15 +81,11 @@ describe("Python Enum", () => {

class Dog:
pass

class Cat:
pass

class Animal(Enum):
DOG = Dog
CAT = Cat


`;
expect(result).toRenderTo(expected);
});
Expand All @@ -117,8 +109,6 @@ describe("Python Enum", () => {
DOG = auto()
CAT = auto()
RABBIT = auto()


`;
expect(result).toRenderTo(expected);
});
Expand Down Expand Up @@ -148,8 +138,6 @@ describe("Python Enum", () => {
READ = 1
WRITE = auto()
EXECUTE = auto()


`;
expect(result).toRenderTo(expected);
});
Expand Down
7 changes: 0 additions & 7 deletions packages/python/test/externals.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,11 @@
response = get(1)
return response.json()


def create_user(user_name: string) -> Response:
response = post(1)
return response.json()


`;
expect(result).toRenderTo(expected);

Check failure on line 105 in packages/python/test/externals.test.tsx

View workflow job for this annotation

GitHub Actions / build

test/externals.test.tsx > uses import from external library in multiple functions

Error: Render is incorrect - Expected + Received @@ -2,10 +2,8 @@ from requests import post from requests.models import Response def get_user(user_id: int) -> Response: response = get(1) - return response.json() - - def create_user(user_name: string) -> Response: + return response.json()def create_user(user_name: string) -> Response: response = post(1) return response.json() ❯ test/externals.test.tsx:105:18
});

it("uses import from external library in multiple class methods", () => {
Expand Down Expand Up @@ -177,13 +174,9 @@
def get_user(self, user_id: int) -> Response:
response = get(self.some_var)
return response.json()

def create_user(self, user_name: string) -> Response:
response = post(self.some_var)
return response.json()



`;
expect(result).toRenderTo(expected);
});
2 changes: 0 additions & 2 deletions packages/python/test/functioncallexpressions.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ describe("FunctionCallExpression", () => {
const expected = d`
def run_func():
pass

run_func("A name", 42, True)
`;
expect(result).toRenderTo(expected);
Expand Down Expand Up @@ -79,7 +78,6 @@ describe("FunctionCallExpression", () => {
const expected = d`
def run_func(name: str, number: int, flag: bool) -> str:
pass

result: str = run_func("A name", 42, True)
`;
expect(result).toRenderTo(expected);
Expand Down
Loading
Loading