@alloy-js/python 0.3.0-dev.3 → 0.3.0-dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,8 +14,16 @@ import { createPythonSymbol } from "../symbol-creation.js";
14
14
  import { PythonOutputSymbol } from "../symbols/index.js";
15
15
  import { Atom } from "./Atom.jsx";
16
16
 
17
+ export type ParameterMarker = "*" | "/";
18
+
19
+ function isParameterMarker(
20
+ param: string | ParameterDescriptor | undefined,
21
+ ): param is ParameterMarker {
22
+ return typeof param === "string" && (param === "*" || param === "/");
23
+ }
24
+
17
25
  export interface CallSignatureParametersProps {
18
- readonly parameters?: (ParameterDescriptor | string)[];
26
+ readonly parameters?: (ParameterDescriptor | ParameterMarker | string)[];
19
27
  readonly args?: boolean;
20
28
  readonly kwargs?: boolean;
21
29
  }
@@ -34,13 +42,11 @@ export interface CallSignatureParametersProps {
34
42
  * ```
35
43
  */
36
44
  export function CallSignatureParameters(props: CallSignatureParametersProps) {
37
- const parameters = normalizeAndDeclareParameters(props.parameters ?? []);
38
-
39
45
  const parameterList = computed(() => {
40
- const params = [];
41
- // Add regular parameters
42
- parameters.forEach((param) => {
43
- params.push(parameter(param));
46
+ const params = (props.parameters ?? []).map((p) => {
47
+ return isParameterMarker(p) ? p : (
48
+ parameter(normalizeAndDeclareParameter(p))
49
+ );
44
50
  });
45
51
 
46
52
  // Add *args if specified
@@ -88,40 +94,39 @@ interface DeclaredParameterDescriptor
88
94
  TypeSlot?: SymbolSlot;
89
95
  }
90
96
 
91
- function normalizeAndDeclareParameters(
92
- parameters: (ParameterDescriptor | string)[],
93
- ): DeclaredParameterDescriptor[] {
94
- return parameters.map((param) => {
95
- if (isParameterDescriptor(param)) {
96
- const TypeSlot = createSymbolSlot();
97
-
98
- const symbol = createPythonSymbol(
99
- param.name,
100
- {
101
- refkeys: param.refkey,
102
- type: TypeSlot.firstSymbol,
103
- },
104
- "parameter",
105
- );
106
-
107
- return {
108
- ...param,
109
- symbol,
110
- TypeSlot,
111
- };
112
- } else {
113
- const symbol = createPythonSymbol(param, {}, "parameter");
114
- return { refkeys: symbol.refkeys, symbol };
115
- }
116
- });
97
+ function normalizeAndDeclareParameter(
98
+ param: ParameterDescriptor | string,
99
+ ): DeclaredParameterDescriptor {
100
+ if (isParameterDescriptor(param)) {
101
+ const TypeSlot = createSymbolSlot();
102
+
103
+ const symbol = createPythonSymbol(
104
+ param.name,
105
+ {
106
+ refkeys: param.refkey,
107
+ type: TypeSlot.firstSymbol,
108
+ },
109
+ "parameter",
110
+ );
111
+
112
+ return {
113
+ ...param,
114
+ symbol,
115
+ TypeSlot,
116
+ };
117
+ } else {
118
+ const symbol = createPythonSymbol(param, {}, "parameter");
119
+ return { symbol };
120
+ }
117
121
  }
118
122
 
119
123
  export interface CallSignatureProps {
120
124
  /**
121
- * The parameters to the call signature. Can be an array of strings (for parameters
122
- * which don't have a type or a default value) or {@link ParameterDescriptor}s.
125
+ * The parameters to the call signature. Can be an array of strings (for simple
126
+ * parameter names), {@link ParameterDescriptor}s, or special markers ("*" for
127
+ * keyword-only, "/" for positional-only).
123
128
  */
124
- parameters?: (ParameterDescriptor | string)[];
129
+ parameters?: (ParameterDescriptor | ParameterMarker | string)[];
125
130
 
126
131
  /**
127
132
  * The type parameters of the call signature, e.g. for a generic function.
@@ -3,7 +3,7 @@ import { enumModule } from "../builtins/python.js";
3
3
  import { createPythonSymbol } from "../symbol-creation.js";
4
4
  import { PythonOutputSymbol } from "../symbols/index.js";
5
5
  import { Atom } from "./Atom.jsx";
6
- import { SimpleInlineMemberComment } from "./PyDoc.jsx";
6
+ import { InlineDoc } from "./PyDoc.jsx";
7
7
 
8
8
  export interface EnumMemberProps {
9
9
  /**
@@ -73,7 +73,7 @@ export function EnumMember(props: EnumMemberProps) {
73
73
  <>
74
74
  '{sym.name}'<Show when={valueCode !== undefined}> : {valueCode}</Show>
75
75
  <Show when={props.doc !== undefined}>
76
- <SimpleInlineMemberComment>{props.doc}</SimpleInlineMemberComment>
76
+ <InlineDoc>{props.doc}</InlineDoc>
77
77
  </Show>
78
78
  </>
79
79
  );
@@ -83,7 +83,7 @@ export function EnumMember(props: EnumMemberProps) {
83
83
  {sym.name}
84
84
  <Show when={valueCode !== undefined}> = {valueCode}</Show>
85
85
  <Show when={props.doc !== undefined}>
86
- <SimpleInlineMemberComment>{props.doc}</SimpleInlineMemberComment>
86
+ <InlineDoc>{props.doc}</InlineDoc>
87
87
  </Show>
88
88
  </>
89
89
  );
@@ -259,6 +259,28 @@ export function PyDoc(props: PyDocProps) {
259
259
  );
260
260
  }
261
261
 
262
+ export interface InlineDocProps {
263
+ children: Children;
264
+ }
265
+
266
+ /**
267
+ * An inline documentation component for attribute docstrings.
268
+ * Unlike PyDoc, this doesn't add a trailing line break after the closing quotes,
269
+ * which is appropriate for documenting consecutive attributes like enum members.
270
+ */
271
+ export function InlineDoc(props: InlineDocProps) {
272
+ return (
273
+ <>
274
+ <hardline />
275
+ {'"""'}
276
+ <hbr />
277
+ {props.children}
278
+ <hbr />
279
+ {'"""'}
280
+ </>
281
+ );
282
+ }
283
+
262
284
  export interface PyDocExampleProps {
263
285
  children: Children;
264
286
  }
@@ -373,14 +395,6 @@ export interface SimpleInlineCommentProps {
373
395
  children: Children;
374
396
  }
375
397
 
376
- export function SimpleInlineMemberComment(props: SimpleInlineCommentProps) {
377
- return (
378
- <>
379
- {" "}#: <Prose>{props.children}</Prose>
380
- </>
381
- );
382
- }
383
-
384
398
  interface GoogleStyleFunctionDocProps extends Omit<FunctionDocProps, "style"> {}
385
399
 
386
400
  /**
package/temp/api.json CHANGED
@@ -831,6 +831,15 @@
831
831
  "text": "ParameterDescriptor",
832
832
  "canonicalReference": "@alloy-js/python!ParameterDescriptor:interface"
833
833
  },
834
+ {
835
+ "kind": "Content",
836
+ "text": " | "
837
+ },
838
+ {
839
+ "kind": "Reference",
840
+ "text": "ParameterMarker",
841
+ "canonicalReference": "@alloy-js/python!ParameterMarker:type"
842
+ },
834
843
  {
835
844
  "kind": "Content",
836
845
  "text": " | string)[]"
@@ -846,7 +855,7 @@
846
855
  "name": "parameters",
847
856
  "propertyTypeTokenRange": {
848
857
  "startIndex": 1,
849
- "endIndex": 4
858
+ "endIndex": 6
850
859
  }
851
860
  }
852
861
  ],
@@ -924,7 +933,7 @@
924
933
  {
925
934
  "kind": "PropertySignature",
926
935
  "canonicalReference": "@alloy-js/python!CallSignatureProps#parameters:member",
927
- "docComment": "/**\n * The parameters to the call signature. Can be an array of strings (for parameters\n * which don't have a type or a default value) or {@link ParameterDescriptor}s.\n */\n",
936
+ "docComment": "/**\n * The parameters to the call signature. Can be an array of strings (for simple\n * parameter names), {@link ParameterDescriptor}s, or special markers (\"*\" for\n * keyword-only, \"/\" for positional-only).\n */\n",
928
937
  "excerptTokens": [
929
938
  {
930
939
  "kind": "Content",
@@ -939,6 +948,15 @@
939
948
  "text": "ParameterDescriptor",
940
949
  "canonicalReference": "@alloy-js/python!ParameterDescriptor:interface"
941
950
  },
951
+ {
952
+ "kind": "Content",
953
+ "text": " | "
954
+ },
955
+ {
956
+ "kind": "Reference",
957
+ "text": "ParameterMarker",
958
+ "canonicalReference": "@alloy-js/python!ParameterMarker:type"
959
+ },
942
960
  {
943
961
  "kind": "Content",
944
962
  "text": " | string)[]"
@@ -954,7 +972,7 @@
954
972
  "name": "parameters",
955
973
  "propertyTypeTokenRange": {
956
974
  "startIndex": 1,
957
- "endIndex": 4
975
+ "endIndex": 6
958
976
  }
959
977
  },
960
978
  {
@@ -5431,6 +5449,99 @@
5431
5449
  ],
5432
5450
  "extendsTokenRanges": []
5433
5451
  },
5452
+ {
5453
+ "kind": "Function",
5454
+ "canonicalReference": "@alloy-js/python!InlineDoc:function(1)",
5455
+ "docComment": "/**\n * An inline documentation component for attribute docstrings.\n * Unlike PyDoc, this doesn't add a trailing line break after the closing quotes,\n * which is appropriate for documenting consecutive attributes like enum members.\n */\n",
5456
+ "excerptTokens": [
5457
+ {
5458
+ "kind": "Content",
5459
+ "text": "export declare function InlineDoc(props: "
5460
+ },
5461
+ {
5462
+ "kind": "Reference",
5463
+ "text": "InlineDocProps",
5464
+ "canonicalReference": "@alloy-js/python!InlineDocProps:interface"
5465
+ },
5466
+ {
5467
+ "kind": "Content",
5468
+ "text": "): "
5469
+ },
5470
+ {
5471
+ "kind": "Reference",
5472
+ "text": "Children",
5473
+ "canonicalReference": "@alloy-js/core!Children:type"
5474
+ },
5475
+ {
5476
+ "kind": "Content",
5477
+ "text": ";"
5478
+ }
5479
+ ],
5480
+ "fileUrlPath": "src/components/PyDoc.tsx",
5481
+ "returnTypeTokenRange": {
5482
+ "startIndex": 3,
5483
+ "endIndex": 4
5484
+ },
5485
+ "releaseTag": "Public",
5486
+ "overloadIndex": 1,
5487
+ "parameters": [
5488
+ {
5489
+ "parameterName": "props",
5490
+ "parameterTypeTokenRange": {
5491
+ "startIndex": 1,
5492
+ "endIndex": 2
5493
+ },
5494
+ "isOptional": false
5495
+ }
5496
+ ],
5497
+ "name": "InlineDoc"
5498
+ },
5499
+ {
5500
+ "kind": "Interface",
5501
+ "canonicalReference": "@alloy-js/python!InlineDocProps:interface",
5502
+ "docComment": "",
5503
+ "excerptTokens": [
5504
+ {
5505
+ "kind": "Content",
5506
+ "text": "export interface InlineDocProps "
5507
+ }
5508
+ ],
5509
+ "fileUrlPath": "src/components/PyDoc.tsx",
5510
+ "releaseTag": "Public",
5511
+ "name": "InlineDocProps",
5512
+ "preserveMemberOrder": false,
5513
+ "members": [
5514
+ {
5515
+ "kind": "PropertySignature",
5516
+ "canonicalReference": "@alloy-js/python!InlineDocProps#children:member",
5517
+ "docComment": "",
5518
+ "excerptTokens": [
5519
+ {
5520
+ "kind": "Content",
5521
+ "text": "children: "
5522
+ },
5523
+ {
5524
+ "kind": "Reference",
5525
+ "text": "Children",
5526
+ "canonicalReference": "@alloy-js/core!Children:type"
5527
+ },
5528
+ {
5529
+ "kind": "Content",
5530
+ "text": ";"
5531
+ }
5532
+ ],
5533
+ "isReadonly": false,
5534
+ "isOptional": false,
5535
+ "releaseTag": "Public",
5536
+ "name": "children",
5537
+ "propertyTypeTokenRange": {
5538
+ "startIndex": 1,
5539
+ "endIndex": 2
5540
+ }
5541
+ }
5542
+ ],
5543
+ "extendsTokenRanges": []
5544
+ },
5434
5545
  {
5435
5546
  "kind": "Function",
5436
5547
  "canonicalReference": "@alloy-js/python!isParameterDescriptor:function(1)",
@@ -7291,6 +7402,32 @@
7291
7402
  ],
7292
7403
  "extendsTokenRanges": []
7293
7404
  },
7405
+ {
7406
+ "kind": "TypeAlias",
7407
+ "canonicalReference": "@alloy-js/python!ParameterMarker:type",
7408
+ "docComment": "",
7409
+ "excerptTokens": [
7410
+ {
7411
+ "kind": "Content",
7412
+ "text": "export type ParameterMarker = "
7413
+ },
7414
+ {
7415
+ "kind": "Content",
7416
+ "text": "\"*\" | \"/\""
7417
+ },
7418
+ {
7419
+ "kind": "Content",
7420
+ "text": ";"
7421
+ }
7422
+ ],
7423
+ "fileUrlPath": "src/components/CallSignature.tsx",
7424
+ "releaseTag": "Public",
7425
+ "name": "ParameterMarker",
7426
+ "typeTokenRange": {
7427
+ "startIndex": 1,
7428
+ "endIndex": 2
7429
+ }
7430
+ },
7294
7431
  {
7295
7432
  "kind": "Function",
7296
7433
  "canonicalReference": "@alloy-js/python!PropertyDeclaration:function(1)",
@@ -9731,53 +9868,6 @@
9731
9868
  ],
9732
9869
  "extendsTokenRanges": []
9733
9870
  },
9734
- {
9735
- "kind": "Function",
9736
- "canonicalReference": "@alloy-js/python!SimpleInlineMemberComment:function(1)",
9737
- "docComment": "",
9738
- "excerptTokens": [
9739
- {
9740
- "kind": "Content",
9741
- "text": "export declare function SimpleInlineMemberComment(props: "
9742
- },
9743
- {
9744
- "kind": "Reference",
9745
- "text": "SimpleInlineCommentProps",
9746
- "canonicalReference": "@alloy-js/python!SimpleInlineCommentProps:interface"
9747
- },
9748
- {
9749
- "kind": "Content",
9750
- "text": "): "
9751
- },
9752
- {
9753
- "kind": "Reference",
9754
- "text": "Children",
9755
- "canonicalReference": "@alloy-js/core!Children:type"
9756
- },
9757
- {
9758
- "kind": "Content",
9759
- "text": ";"
9760
- }
9761
- ],
9762
- "fileUrlPath": "src/components/PyDoc.tsx",
9763
- "returnTypeTokenRange": {
9764
- "startIndex": 3,
9765
- "endIndex": 4
9766
- },
9767
- "releaseTag": "Public",
9768
- "overloadIndex": 1,
9769
- "parameters": [
9770
- {
9771
- "parameterName": "props",
9772
- "parameterTypeTokenRange": {
9773
- "startIndex": 1,
9774
- "endIndex": 2
9775
- },
9776
- "isOptional": false
9777
- }
9778
- ],
9779
- "name": "SimpleInlineMemberComment"
9780
- },
9781
9871
  {
9782
9872
  "kind": "Function",
9783
9873
  "canonicalReference": "@alloy-js/python!SourceFile:function(1)",
@@ -96,6 +96,35 @@ describe("Call Signature Parameters", () => {
96
96
  a: int = 5, b: str = "hello"
97
97
  `);
98
98
  });
99
+ it("renders keyword-only parameters with * marker", () => {
100
+ const result = toSourceText([
101
+ <py.CallSignatureParameters
102
+ parameters={[
103
+ { name: "a", type: "str" },
104
+ "*",
105
+ { name: "b", type: "int", default: 10 },
106
+ { name: "c", type: "bool", default: true },
107
+ ]}
108
+ />,
109
+ ]);
110
+ expect(result).toRenderTo(d`
111
+ a: str, *, b: int = 10, c: bool = True
112
+ `);
113
+ });
114
+ it("renders only keyword-only parameters with * marker at start", () => {
115
+ const result = toSourceText([
116
+ <py.CallSignatureParameters
117
+ parameters={[
118
+ "*",
119
+ { name: "a", type: "str", default: "hello" },
120
+ { name: "b", type: "int", default: 42 },
121
+ ]}
122
+ />,
123
+ ]);
124
+ expect(result).toRenderTo(d`
125
+ *, a: str = "hello", b: int = 42
126
+ `);
127
+ });
99
128
  });
100
129
 
101
130
  describe("Call Signature", () => {
@@ -281,4 +310,85 @@ describe("Call Signature - Parameter Descriptors", () => {
281
310
  [T, U](a: int, b: str = "default_value") -> int
282
311
  `);
283
312
  });
313
+ it("renders a call signature with keyword-only parameters using * marker", () => {
314
+ const result = toSourceText([
315
+ <py.CallSignature
316
+ parameters={[
317
+ { name: "id", type: "str" },
318
+ "*",
319
+ { name: "locale", type: "str", default: "en-US" },
320
+ { name: "debug", type: "bool", default: false },
321
+ ]}
322
+ returnType="str"
323
+ />,
324
+ ]);
325
+ expect(result).toRenderTo(d`
326
+ (id: str, *, locale: str = "en-US", debug: bool = False) -> str
327
+ `);
328
+ });
329
+ it("renders a call signature with only keyword-only parameters", () => {
330
+ const result = toSourceText([
331
+ <py.CallSignature
332
+ parameters={[
333
+ "*",
334
+ { name: "name", type: "str", default: "alice" },
335
+ { name: "age", type: "int", default: 30 },
336
+ ]}
337
+ returnType="None"
338
+ />,
339
+ ]);
340
+ expect(result).toRenderTo(d`
341
+ (*, name: str = "alice", age: int = 30) -> None
342
+ `);
343
+ });
344
+ it("renders a call signature with positional, keyword-only, and *args/**kwargs", () => {
345
+ const result = toSourceText([
346
+ <py.CallSignature
347
+ parameters={[
348
+ { name: "a", type: "int" },
349
+ "*",
350
+ { name: "b", type: "str", default: "hello" },
351
+ ]}
352
+ args
353
+ kwargs
354
+ returnType="None"
355
+ />,
356
+ ]);
357
+ expect(result).toRenderTo(d`
358
+ (a: int, *, b: str = "hello", *args, **kwargs) -> None
359
+ `);
360
+ });
361
+ it("renders a call signature with positional-only parameters using / marker", () => {
362
+ const result = toSourceText([
363
+ <py.CallSignature
364
+ parameters={[
365
+ { name: "a", type: "int" },
366
+ { name: "b", type: "str" },
367
+ "/",
368
+ { name: "c", type: "bool" },
369
+ ]}
370
+ returnType="None"
371
+ />,
372
+ ]);
373
+ expect(result).toRenderTo(d`
374
+ (a: int, b: str, /, c: bool) -> None
375
+ `);
376
+ });
377
+ it("renders a call signature with positional-only, regular, and keyword-only parameters", () => {
378
+ const result = toSourceText([
379
+ <py.CallSignature
380
+ parameters={[
381
+ { name: "a", type: "int" },
382
+ "/",
383
+ { name: "b", type: "str" },
384
+ "*",
385
+ { name: "c", type: "bool", default: true },
386
+ ]}
387
+ returnType="None"
388
+ />,
389
+ ]);
390
+ expect(result).toRenderTo(d`
391
+ (a: int, /, b: str, *, c: bool = True) -> None
392
+ `);
393
+ });
284
394
  });
@@ -195,40 +195,6 @@ describe("SimpleInlineComment", () => {
195
195
  });
196
196
  });
197
197
 
198
- describe("SimpleInlineMemberComment", () => {
199
- it("renders inline member comment", () => {
200
- const res = toSourceText([
201
- <>
202
- status: int
203
- <py.SimpleInlineMemberComment>
204
- HTTP status code
205
- </py.SimpleInlineMemberComment>
206
- </>,
207
- ]);
208
- expect(res).toRenderTo(
209
- d`
210
- status: int #: HTTP status code
211
- `,
212
- );
213
- });
214
-
215
- it("renders inline member comment for variable declaration", () => {
216
- const res = toSourceText([
217
- <>
218
- max_retries = 3
219
- <py.SimpleInlineMemberComment>
220
- Maximum number of retry attempts
221
- </py.SimpleInlineMemberComment>
222
- </>,
223
- ]);
224
- expect(res).toRenderTo(
225
- d`
226
- max_retries = 3 #: Maximum number of retry attempts
227
- `,
228
- );
229
- });
230
- });
231
-
232
198
  describe("New Documentation Components", () => {
233
199
  it("ModuleDoc renders correctly", () => {
234
200
  const res = toSourceText([
@@ -1177,9 +1143,18 @@ describe("Full example", () => {
1177
1143
  An enum representing colors.
1178
1144
  """
1179
1145
 
1180
- RED = 1 #: The color red.
1181
- GREEN = 2 #: The color green.
1182
- BLUE = 3 #: The color blue.
1146
+ RED = 1
1147
+ """
1148
+ The color red.
1149
+ """
1150
+ GREEN = 2
1151
+ """
1152
+ The color green.
1153
+ """
1154
+ BLUE = 3
1155
+ """
1156
+ The color blue.
1157
+ """
1183
1158
 
1184
1159
 
1185
1160
  `;