tywrap 0.5.1 → 0.6.1

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.
Files changed (178) hide show
  1. package/dist/cli.js +8 -6
  2. package/dist/cli.js.map +1 -1
  3. package/dist/config/index.d.ts.map +1 -1
  4. package/dist/config/index.js +236 -147
  5. package/dist/config/index.js.map +1 -1
  6. package/dist/core/annotation-parser.d.ts.map +1 -1
  7. package/dist/core/annotation-parser.js +112 -97
  8. package/dist/core/annotation-parser.js.map +1 -1
  9. package/dist/core/discovery.d.ts +17 -0
  10. package/dist/core/discovery.d.ts.map +1 -1
  11. package/dist/core/discovery.js +85 -49
  12. package/dist/core/discovery.js.map +1 -1
  13. package/dist/core/emit-call.d.ts +58 -0
  14. package/dist/core/emit-call.d.ts.map +1 -0
  15. package/dist/core/emit-call.js +103 -0
  16. package/dist/core/emit-call.js.map +1 -0
  17. package/dist/core/generator.d.ts +2 -0
  18. package/dist/core/generator.d.ts.map +1 -1
  19. package/dist/core/generator.js +54 -211
  20. package/dist/core/generator.js.map +1 -1
  21. package/dist/core/mapper.d.ts.map +1 -1
  22. package/dist/core/mapper.js +118 -104
  23. package/dist/core/mapper.js.map +1 -1
  24. package/dist/core/validation.d.ts +23 -0
  25. package/dist/core/validation.d.ts.map +1 -1
  26. package/dist/core/validation.js +52 -48
  27. package/dist/core/validation.js.map +1 -1
  28. package/dist/dev.d.ts.map +1 -1
  29. package/dist/dev.js +175 -133
  30. package/dist/dev.js.map +1 -1
  31. package/dist/index.d.ts +6 -25
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +9 -31
  34. package/dist/index.js.map +1 -1
  35. package/dist/runtime/bounded-context.d.ts +2 -2
  36. package/dist/runtime/bounded-context.js +2 -2
  37. package/dist/runtime/{safe-codec.d.ts → bridge-codec.d.ts} +26 -11
  38. package/dist/runtime/bridge-codec.d.ts.map +1 -0
  39. package/dist/runtime/{safe-codec.js → bridge-codec.js} +69 -72
  40. package/dist/runtime/bridge-codec.js.map +1 -0
  41. package/dist/runtime/{http-io.d.ts → http-transport.d.ts} +6 -6
  42. package/dist/runtime/http-transport.d.ts.map +1 -0
  43. package/dist/runtime/{http-io.js → http-transport.js} +3 -3
  44. package/dist/runtime/http-transport.js.map +1 -0
  45. package/dist/runtime/http.d.ts +3 -3
  46. package/dist/runtime/http.d.ts.map +1 -1
  47. package/dist/runtime/http.js +4 -4
  48. package/dist/runtime/http.js.map +1 -1
  49. package/dist/runtime/index.d.ts +9 -1
  50. package/dist/runtime/index.d.ts.map +1 -1
  51. package/dist/runtime/index.js +9 -1
  52. package/dist/runtime/index.js.map +1 -1
  53. package/dist/runtime/node.d.ts +6 -6
  54. package/dist/runtime/node.d.ts.map +1 -1
  55. package/dist/runtime/node.js +7 -7
  56. package/dist/runtime/node.js.map +1 -1
  57. package/dist/runtime/pooled-transport.d.ts +11 -11
  58. package/dist/runtime/pooled-transport.d.ts.map +1 -1
  59. package/dist/runtime/pooled-transport.js +10 -10
  60. package/dist/runtime/pooled-transport.js.map +1 -1
  61. package/dist/runtime/pyodide-bootstrap-core.generated.d.ts.map +1 -1
  62. package/dist/runtime/pyodide-bootstrap-core.generated.js +1 -1
  63. package/dist/runtime/pyodide-bootstrap-core.generated.js.map +1 -1
  64. package/dist/runtime/{pyodide-io.d.ts → pyodide-transport.d.ts} +8 -8
  65. package/dist/runtime/pyodide-transport.d.ts.map +1 -0
  66. package/dist/runtime/{pyodide-io.js → pyodide-transport.js} +5 -5
  67. package/dist/runtime/pyodide-transport.js.map +1 -0
  68. package/dist/runtime/pyodide.d.ts +3 -3
  69. package/dist/runtime/pyodide.d.ts.map +1 -1
  70. package/dist/runtime/pyodide.js +5 -5
  71. package/dist/runtime/pyodide.js.map +1 -1
  72. package/dist/runtime/rpc-client.d.ts +23 -5
  73. package/dist/runtime/rpc-client.d.ts.map +1 -1
  74. package/dist/runtime/rpc-client.js +36 -31
  75. package/dist/runtime/rpc-client.js.map +1 -1
  76. package/dist/runtime/{process-io.d.ts → subprocess-transport.d.ts} +25 -9
  77. package/dist/runtime/subprocess-transport.d.ts.map +1 -0
  78. package/dist/runtime/{process-io.js → subprocess-transport.js} +60 -41
  79. package/dist/runtime/subprocess-transport.js.map +1 -0
  80. package/dist/runtime/{worker-pool.d.ts → transport-pool.d.ts} +15 -15
  81. package/dist/runtime/transport-pool.d.ts.map +1 -0
  82. package/dist/runtime/{worker-pool.js → transport-pool.js} +6 -6
  83. package/dist/runtime/transport-pool.js.map +1 -0
  84. package/dist/runtime/transport.d.ts +14 -8
  85. package/dist/runtime/transport.d.ts.map +1 -1
  86. package/dist/runtime/transport.js +10 -4
  87. package/dist/runtime/transport.js.map +1 -1
  88. package/dist/types/index.d.ts +10 -1
  89. package/dist/types/index.d.ts.map +1 -1
  90. package/dist/tywrap.d.ts +0 -5
  91. package/dist/tywrap.d.ts.map +1 -1
  92. package/dist/tywrap.js +0 -20
  93. package/dist/tywrap.js.map +1 -1
  94. package/dist/utils/cache.d.ts +13 -2
  95. package/dist/utils/cache.d.ts.map +1 -1
  96. package/dist/utils/cache.js +52 -60
  97. package/dist/utils/cache.js.map +1 -1
  98. package/dist/utils/codec.d.ts +1 -1
  99. package/dist/utils/codec.d.ts.map +1 -1
  100. package/dist/utils/codec.js +181 -182
  101. package/dist/utils/codec.js.map +1 -1
  102. package/dist/utils/python.d.ts.map +1 -1
  103. package/dist/utils/python.js +28 -17
  104. package/dist/utils/python.js.map +1 -1
  105. package/dist/utils/runtime.d.ts.map +1 -1
  106. package/dist/utils/runtime.js +22 -16
  107. package/dist/utils/runtime.js.map +1 -1
  108. package/dist/version.d.ts +12 -0
  109. package/dist/version.d.ts.map +1 -0
  110. package/dist/version.js +12 -0
  111. package/dist/version.js.map +1 -0
  112. package/package.json +3 -2
  113. package/runtime/__pycache__/safe_codec.cpython-311.pyc +0 -0
  114. package/runtime/__pycache__/tywrap_bridge_core.cpython-311.pyc +0 -0
  115. package/runtime/python_bridge.py +54 -6
  116. package/runtime/safe_codec.py +8 -8
  117. package/runtime/tywrap_bridge_core.py +159 -23
  118. package/src/cli.ts +8 -12
  119. package/src/config/index.ts +271 -165
  120. package/src/core/annotation-parser.ts +135 -123
  121. package/src/core/discovery.ts +102 -54
  122. package/src/core/emit-call.ts +171 -0
  123. package/src/core/generator.ts +67 -263
  124. package/src/core/mapper.ts +125 -110
  125. package/src/core/validation.ts +84 -48
  126. package/src/dev.ts +237 -153
  127. package/src/index.ts +11 -68
  128. package/src/runtime/bounded-context.ts +2 -2
  129. package/src/runtime/{safe-codec.ts → bridge-codec.ts} +83 -95
  130. package/src/runtime/{http-io.ts → http-transport.ts} +5 -5
  131. package/src/runtime/http.ts +5 -5
  132. package/src/runtime/index.ts +23 -1
  133. package/src/runtime/node.ts +15 -15
  134. package/src/runtime/pooled-transport.ts +15 -15
  135. package/src/runtime/pyodide-bootstrap-core.generated.ts +1 -1
  136. package/src/runtime/{pyodide-io.ts → pyodide-transport.ts} +7 -7
  137. package/src/runtime/pyodide.ts +6 -6
  138. package/src/runtime/rpc-client.ts +51 -40
  139. package/src/runtime/{process-io.ts → subprocess-transport.ts} +77 -47
  140. package/src/runtime/{worker-pool.ts → transport-pool.ts} +26 -26
  141. package/src/runtime/transport.ts +15 -8
  142. package/src/types/index.ts +10 -1
  143. package/src/tywrap.ts +0 -24
  144. package/src/utils/cache.ts +61 -63
  145. package/src/utils/codec.ts +217 -196
  146. package/src/utils/python.ts +33 -20
  147. package/src/utils/runtime.ts +24 -13
  148. package/src/version.ts +12 -0
  149. package/dist/runtime/http-io.d.ts.map +0 -1
  150. package/dist/runtime/http-io.js.map +0 -1
  151. package/dist/runtime/optimized-node.d.ts +0 -23
  152. package/dist/runtime/optimized-node.d.ts.map +0 -1
  153. package/dist/runtime/optimized-node.js +0 -23
  154. package/dist/runtime/optimized-node.js.map +0 -1
  155. package/dist/runtime/process-io.d.ts.map +0 -1
  156. package/dist/runtime/process-io.js.map +0 -1
  157. package/dist/runtime/protocol.d.ts +0 -3
  158. package/dist/runtime/protocol.d.ts.map +0 -1
  159. package/dist/runtime/protocol.js +0 -3
  160. package/dist/runtime/protocol.js.map +0 -1
  161. package/dist/runtime/pyodide-io.d.ts.map +0 -1
  162. package/dist/runtime/pyodide-io.js.map +0 -1
  163. package/dist/runtime/safe-codec.d.ts.map +0 -1
  164. package/dist/runtime/safe-codec.js.map +0 -1
  165. package/dist/runtime/worker-pool.d.ts.map +0 -1
  166. package/dist/runtime/worker-pool.js.map +0 -1
  167. package/dist/utils/bundle-optimizer.d.ts +0 -182
  168. package/dist/utils/bundle-optimizer.d.ts.map +0 -1
  169. package/dist/utils/bundle-optimizer.js +0 -680
  170. package/dist/utils/bundle-optimizer.js.map +0 -1
  171. package/dist/utils/memory-profiler.d.ts +0 -123
  172. package/dist/utils/memory-profiler.d.ts.map +0 -1
  173. package/dist/utils/memory-profiler.js +0 -426
  174. package/dist/utils/memory-profiler.js.map +0 -1
  175. package/src/runtime/optimized-node.ts +0 -25
  176. package/src/runtime/protocol.ts +0 -2
  177. package/src/utils/bundle-optimizer.ts +0 -876
  178. package/src/utils/memory-profiler.ts +0 -582
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Shared call-emission helpers for the TypeScript wrapper generator.
3
+ *
4
+ * The function, method, and constructor wrappers all emit the same runtime
5
+ * prelude (assemble `__args`, fold a trailing object into `__kwargs`, unpack
6
+ * `*args`) and the same argument guards (reject positional-only-as-keyword,
7
+ * require keyword-only arguments). They differ only by indentation, the error
8
+ * label used in thrown messages, and the terminal RPC verb (which the call
9
+ * sites still emit themselves).
10
+ *
11
+ * The emitted strings MUST stay byte-identical to the previous inline copies.
12
+ */
13
+
14
+ import type { Parameter } from '../types/index.js';
15
+
16
+ /** Describes one call site for prelude/guard emission. */
17
+ export interface CallDescriptor {
18
+ /** Positional parameters (no *args/**kwargs/keyword-only). */
19
+ positionalParams: readonly Parameter[];
20
+ /** The `*args` parameter, if any. */
21
+ varArgsParam?: Parameter;
22
+ /** Whether `*args` is modeled as an array param (true when kwargs coexist). */
23
+ needsVarArgsArray: boolean;
24
+ /** Whether the wrapper takes a `kwargs` parameter. */
25
+ hasKwArgs: boolean;
26
+ /** Whether the callee declares `**kwargs`. */
27
+ hasVarKwArgs: boolean;
28
+ /** Names of keyword-only parameters. */
29
+ keywordOnlyNames: readonly string[];
30
+ /** Names of required keyword-only parameters. */
31
+ requiredKwOnlyNames: readonly string[];
32
+ /** Names of positional-only parameters. */
33
+ positionalOnlyNames: readonly string[];
34
+ /** Number of leading required positional parameters. */
35
+ requiredPosCount: number;
36
+ /** Base indentation (e.g. ' ' for functions, ' ' for methods/ctors). */
37
+ indent: string;
38
+ /** Error label used in thrown messages (function/method name or '__init__'). */
39
+ errorLabel: string;
40
+ }
41
+
42
+ /** Helpers wired from the generator instance (they depend on `this`). */
43
+ export interface CallEmitHelpers {
44
+ escapeIdentifier(name: string): string;
45
+ renderLooksLikeKwargsExpr(
46
+ valueExpr: string,
47
+ options: {
48
+ keywordOnlyNames: string[];
49
+ requiredKwOnlyNames: string[];
50
+ hasVarKwArgs: boolean;
51
+ }
52
+ ): string;
53
+ }
54
+
55
+ /**
56
+ * Emit the runtime prelude lines that build the `__args` array, fold a trailing
57
+ * plain object into `__kwargs`, and unpack `*args`.
58
+ */
59
+ export function emitCallPrelude(desc: CallDescriptor, helpers: CallEmitHelpers): string[] {
60
+ const {
61
+ positionalParams,
62
+ varArgsParam,
63
+ needsVarArgsArray,
64
+ hasKwArgs,
65
+ hasVarKwArgs,
66
+ keywordOnlyNames,
67
+ requiredKwOnlyNames,
68
+ requiredPosCount,
69
+ indent: i,
70
+ errorLabel,
71
+ } = desc;
72
+ const i2 = `${i} `;
73
+ const i3 = `${i2} `;
74
+
75
+ const lines: string[] = [];
76
+ if (hasKwArgs) {
77
+ lines.push(`${i}let __kwargs = kwargs;`);
78
+ }
79
+ const positionalArgExprs = positionalParams.map(p => helpers.escapeIdentifier(p.name));
80
+ lines.push(`${i}const __args: unknown[] = [${positionalArgExprs.join(', ')}];`);
81
+ if (requiredPosCount < positionalParams.length) {
82
+ lines.push(
83
+ `${i}while (__args.length > ${requiredPosCount} && __args[__args.length - 1] === undefined) {`
84
+ );
85
+ lines.push(`${i2}__args.pop();`);
86
+ lines.push(`${i}}`);
87
+ }
88
+ if (hasKwArgs && requiredPosCount < positionalParams.length) {
89
+ const looksLikeKwargs = helpers.renderLooksLikeKwargsExpr('__candidate', {
90
+ keywordOnlyNames: [...keywordOnlyNames],
91
+ requiredKwOnlyNames: [...requiredKwOnlyNames],
92
+ hasVarKwArgs,
93
+ });
94
+ lines.push(`${i}if (__kwargs === undefined && __args.length > ${requiredPosCount}) {`);
95
+ lines.push(`${i2}const __candidate = __args[__args.length - 1];`);
96
+ lines.push(`${i2}if (${looksLikeKwargs}) {`);
97
+ lines.push(`${i3}__kwargs = __candidate as any;`);
98
+ lines.push(`${i3}__args.pop();`);
99
+ lines.push(`${i2}}`);
100
+ lines.push(`${i}}`);
101
+ }
102
+ if (varArgsParam) {
103
+ const vname = helpers.escapeIdentifier(varArgsParam.name);
104
+ if (needsVarArgsArray) {
105
+ const looksLikeKwargs = helpers.renderLooksLikeKwargsExpr(vname, {
106
+ keywordOnlyNames: [...keywordOnlyNames],
107
+ requiredKwOnlyNames: [...requiredKwOnlyNames],
108
+ hasVarKwArgs,
109
+ });
110
+ lines.push(`${i}let __varargs: unknown[] = [];`);
111
+ lines.push(`${i}if (${vname} !== undefined) {`);
112
+ lines.push(`${i2}if (globalThis.Array.isArray(${vname})) {`);
113
+ lines.push(`${i3}__varargs = ${vname};`);
114
+ lines.push(`${i2}} else if (__kwargs === undefined && ${looksLikeKwargs}) {`);
115
+ lines.push(`${i3}__kwargs = ${vname} as any;`);
116
+ lines.push(`${i2}} else {`);
117
+ lines.push(
118
+ `${i3}throw new Error(\`${errorLabel} expected ${varArgsParam.name} to be an array\`);`
119
+ );
120
+ lines.push(`${i2}}`);
121
+ lines.push(`${i}}`);
122
+ lines.push(`${i}__args.push(...__varargs);`);
123
+ } else {
124
+ lines.push(`${i}__args.push(...${vname});`);
125
+ }
126
+ }
127
+ return lines;
128
+ }
129
+
130
+ /**
131
+ * Emit the argument guard lines that reject positional-only arguments passed as
132
+ * keywords and enforce required keyword-only arguments.
133
+ */
134
+ export function emitArgGuards(desc: CallDescriptor): string[] {
135
+ const {
136
+ hasKwArgs,
137
+ positionalOnlyNames,
138
+ requiredKwOnlyNames,
139
+ indent: i,
140
+ errorLabel,
141
+ } = desc;
142
+ const i2 = `${i} `;
143
+ const i3 = `${i2} `;
144
+
145
+ const lines: string[] = [];
146
+ if (hasKwArgs && positionalOnlyNames.length > 0) {
147
+ lines.push(`${i}const __positionalOnly = ${JSON.stringify(positionalOnlyNames)} as const;`);
148
+ lines.push(`${i}for (const key of __positionalOnly) {`);
149
+ lines.push(`${i2}if (__kwargs && Object.prototype.hasOwnProperty.call(__kwargs, key)) {`);
150
+ lines.push(
151
+ `${i3}throw new Error(\`${errorLabel} does not accept positional-only argument "\${key}" as a keyword argument\`);`
152
+ );
153
+ lines.push(`${i2}}`);
154
+ lines.push(`${i}}`);
155
+ }
156
+ if (hasKwArgs && requiredKwOnlyNames.length > 0) {
157
+ lines.push(`${i}const __requiredKwOnly = ${JSON.stringify(requiredKwOnlyNames)} as const;`);
158
+ lines.push(`${i}const __missing: string[] = [];`);
159
+ lines.push(`${i}for (const key of __requiredKwOnly) {`);
160
+ lines.push(`${i2}if (!__kwargs || !Object.prototype.hasOwnProperty.call(__kwargs, key)) {`);
161
+ lines.push(`${i3}__missing.push(key);`);
162
+ lines.push(`${i2}}`);
163
+ lines.push(`${i}}`);
164
+ lines.push(`${i}if (__missing.length > 0) {`);
165
+ lines.push(
166
+ `${i2}throw new Error(\`Missing required keyword-only arguments for ${errorLabel}: \${__missing.join(', ')}\`);`
167
+ );
168
+ lines.push(`${i}}`);
169
+ }
170
+ return lines;
171
+ }
@@ -14,6 +14,12 @@ import type {
14
14
  } from '../types/index.js';
15
15
  import { globalCache } from '../utils/cache.js';
16
16
 
17
+ import {
18
+ emitArgGuards,
19
+ emitCallPrelude,
20
+ type CallDescriptor,
21
+ type CallEmitHelpers,
22
+ } from './emit-call.js';
17
23
  import { TypeMapper } from './mapper.js';
18
24
 
19
25
  interface GenericRenderParam {
@@ -336,6 +342,21 @@ export class CodeGenerator {
336
342
  return `(${base} && (${keyCheck}))`;
337
343
  }
338
344
 
345
+ /** Helpers passed to the shared call-emission module (they depend on `this`). */
346
+ private callEmitHelpers(): CallEmitHelpers {
347
+ return {
348
+ escapeIdentifier: (name: string): string => this.escapeIdentifier(name),
349
+ renderLooksLikeKwargsExpr: (
350
+ valueExpr: string,
351
+ options: {
352
+ keywordOnlyNames: string[];
353
+ requiredKwOnlyNames: string[];
354
+ hasVarKwArgs: boolean;
355
+ }
356
+ ): string => this.renderLooksLikeKwargsExpr(valueExpr, options),
357
+ };
358
+ }
359
+
339
360
  generateFunctionWrapper(
340
361
  func: PythonFunction,
341
362
  moduleName?: string,
@@ -492,96 +513,26 @@ export class CodeGenerator {
492
513
  }
493
514
 
494
515
  const overloadDecl = overloads.length > 0 ? `${overloads.join('\n')}\n` : '';
495
- const guardLines: string[] = [];
496
- if (hasKwArgs && positionalOnlyNames.length > 0) {
497
- guardLines.push(
498
- ` const __positionalOnly = ${JSON.stringify(positionalOnlyNames)} as const;`
499
- );
500
- guardLines.push(` for (const key of __positionalOnly) {`);
501
- guardLines.push(` if (__kwargs && Object.prototype.hasOwnProperty.call(__kwargs, key)) {`);
502
- guardLines.push(
503
- ` throw new Error(\`${func.name} does not accept positional-only argument "\${key}" as a keyword argument\`);`
504
- );
505
- guardLines.push(` }`);
506
- guardLines.push(` }`);
507
- }
508
- if (hasKwArgs && requiredKwOnlyNames.length > 0) {
509
- guardLines.push(
510
- ` const __requiredKwOnly = ${JSON.stringify(requiredKwOnlyNames)} as const;`
511
- );
512
- guardLines.push(` const __missing: string[] = [];`);
513
- guardLines.push(` for (const key of __requiredKwOnly) {`);
514
- guardLines.push(
515
- ` if (!__kwargs || !Object.prototype.hasOwnProperty.call(__kwargs, key)) {`
516
- );
517
- guardLines.push(` __missing.push(key);`);
518
- guardLines.push(` }`);
519
- guardLines.push(` }`);
520
- guardLines.push(` if (__missing.length > 0) {`);
521
- guardLines.push(
522
- ` throw new Error(\`Missing required keyword-only arguments for ${func.name}: \${__missing.join(', ')}\`);`
523
- );
524
- guardLines.push(` }`);
525
- }
526
- const guards = guardLines.length > 0 ? `${guardLines.join('\n')}\n` : '';
527
516
 
528
517
  const firstOptionalPosIndex = positionalParams.findIndex(p => p.optional);
529
518
  const requiredPosCount =
530
519
  firstOptionalPosIndex >= 0 ? firstOptionalPosIndex : positionalParams.length;
531
- const callPreludeLines: string[] = [];
532
- if (hasKwArgs) {
533
- callPreludeLines.push(` let __kwargs = kwargs;`);
534
- }
535
- const positionalArgExprs = positionalParams.map(p => this.escapeIdentifier(p.name));
536
- callPreludeLines.push(` const __args: unknown[] = [${positionalArgExprs.join(', ')}];`);
537
- if (requiredPosCount < positionalParams.length) {
538
- callPreludeLines.push(
539
- ` while (__args.length > ${requiredPosCount} && __args[__args.length - 1] === undefined) {`
540
- );
541
- callPreludeLines.push(` __args.pop();`);
542
- callPreludeLines.push(` }`);
543
- }
544
- if (hasKwArgs && requiredPosCount < positionalParams.length) {
545
- const looksLikeKwargs = this.renderLooksLikeKwargsExpr('__candidate', {
546
- keywordOnlyNames,
547
- requiredKwOnlyNames,
548
- hasVarKwArgs,
549
- });
550
- callPreludeLines.push(
551
- ` if (__kwargs === undefined && __args.length > ${requiredPosCount}) {`
552
- );
553
- callPreludeLines.push(` const __candidate = __args[__args.length - 1];`);
554
- callPreludeLines.push(` if (${looksLikeKwargs}) {`);
555
- callPreludeLines.push(` __kwargs = __candidate as any;`);
556
- callPreludeLines.push(` __args.pop();`);
557
- callPreludeLines.push(` }`);
558
- callPreludeLines.push(` }`);
559
- }
560
- if (varArgsParam) {
561
- const vname = this.escapeIdentifier(varArgsParam.name);
562
- if (needsVarArgsArray) {
563
- const looksLikeKwargs = this.renderLooksLikeKwargsExpr(vname, {
564
- keywordOnlyNames,
565
- requiredKwOnlyNames,
566
- hasVarKwArgs,
567
- });
568
- callPreludeLines.push(` let __varargs: unknown[] = [];`);
569
- callPreludeLines.push(` if (${vname} !== undefined) {`);
570
- callPreludeLines.push(` if (globalThis.Array.isArray(${vname})) {`);
571
- callPreludeLines.push(` __varargs = ${vname};`);
572
- callPreludeLines.push(` } else if (__kwargs === undefined && ${looksLikeKwargs}) {`);
573
- callPreludeLines.push(` __kwargs = ${vname} as any;`);
574
- callPreludeLines.push(` } else {`);
575
- callPreludeLines.push(
576
- ` throw new Error(\`${func.name} expected ${varArgsParam.name} to be an array\`);`
577
- );
578
- callPreludeLines.push(` }`);
579
- callPreludeLines.push(` }`);
580
- callPreludeLines.push(` __args.push(...__varargs);`);
581
- } else {
582
- callPreludeLines.push(` __args.push(...${vname});`);
583
- }
584
- }
520
+ const callDescriptor: CallDescriptor = {
521
+ positionalParams,
522
+ varArgsParam,
523
+ needsVarArgsArray,
524
+ hasKwArgs,
525
+ hasVarKwArgs,
526
+ keywordOnlyNames,
527
+ requiredKwOnlyNames,
528
+ positionalOnlyNames,
529
+ requiredPosCount,
530
+ indent: ' ',
531
+ errorLabel: func.name,
532
+ };
533
+ const guardLines = emitArgGuards(callDescriptor);
534
+ const guards = guardLines.length > 0 ? `${guardLines.join('\n')}\n` : '';
535
+ const callPreludeLines = emitCallPrelude(callDescriptor, this.callEmitHelpers());
585
536
  const callPrelude = callPreludeLines.length > 0 ? `${callPreludeLines.join('\n')}\n` : '';
586
537
 
587
538
  const ts = `${jsdoc}${overloadDecl}export async function ${fname}${typeParamDecl}(${paramDecl}): Promise<${returnType}> {
@@ -797,97 +748,23 @@ ${callPrelude}${guards} return getRuntimeBridge().call('${moduleId}', '${func.n
797
748
  }
798
749
  const overloadDecl = overloads.length > 0 ? `${overloads.join('\n')}\n` : '';
799
750
 
800
- const callPreludeLines: string[] = [];
801
- if (needsKwargsParam) {
802
- callPreludeLines.push(` let __kwargs = kwargs;`);
803
- }
804
- const positionalArgExprs = positionalParams.map(p => this.escapeIdentifier(p.name));
805
- callPreludeLines.push(` const __args: unknown[] = [${positionalArgExprs.join(', ')}];`);
806
- if (requiredPosCount < positionalParams.length) {
807
- callPreludeLines.push(
808
- ` while (__args.length > ${requiredPosCount} && __args[__args.length - 1] === undefined) {`
809
- );
810
- callPreludeLines.push(` __args.pop();`);
811
- callPreludeLines.push(` }`);
812
- }
813
- if (needsKwargsParam && requiredPosCount < positionalParams.length) {
814
- const looksLikeKwargs = this.renderLooksLikeKwargsExpr('__candidate', {
815
- keywordOnlyNames,
816
- requiredKwOnlyNames,
817
- hasVarKwArgs,
818
- });
819
- callPreludeLines.push(
820
- ` if (__kwargs === undefined && __args.length > ${requiredPosCount}) {`
821
- );
822
- callPreludeLines.push(` const __candidate = __args[__args.length - 1];`);
823
- callPreludeLines.push(` if (${looksLikeKwargs}) {`);
824
- callPreludeLines.push(` __kwargs = __candidate as any;`);
825
- callPreludeLines.push(` __args.pop();`);
826
- callPreludeLines.push(` }`);
827
- callPreludeLines.push(` }`);
828
- }
829
- if (varArgsParam) {
830
- const vname = this.escapeIdentifier(varArgsParam.name);
831
- if (needsVarArgsArray) {
832
- const looksLikeKwargs = this.renderLooksLikeKwargsExpr(vname, {
833
- keywordOnlyNames,
834
- requiredKwOnlyNames,
835
- hasVarKwArgs,
836
- });
837
- callPreludeLines.push(` let __varargs: unknown[] = [];`);
838
- callPreludeLines.push(` if (${vname} !== undefined) {`);
839
- callPreludeLines.push(` if (globalThis.Array.isArray(${vname})) {`);
840
- callPreludeLines.push(` __varargs = ${vname};`);
841
- callPreludeLines.push(
842
- ` } else if (__kwargs === undefined && ${looksLikeKwargs}) {`
843
- );
844
- callPreludeLines.push(` __kwargs = ${vname} as any;`);
845
- callPreludeLines.push(` } else {`);
846
- callPreludeLines.push(
847
- ` throw new Error(\`${method.name} expected ${varArgsParam.name} to be an array\`);`
848
- );
849
- callPreludeLines.push(` }`);
850
- callPreludeLines.push(` }`);
851
- callPreludeLines.push(` __args.push(...__varargs);`);
852
- } else {
853
- callPreludeLines.push(` __args.push(...${vname});`);
854
- }
855
- }
751
+ const callDescriptor: CallDescriptor = {
752
+ positionalParams,
753
+ varArgsParam,
754
+ needsVarArgsArray,
755
+ hasKwArgs: needsKwargsParam,
756
+ hasVarKwArgs,
757
+ keywordOnlyNames,
758
+ requiredKwOnlyNames,
759
+ positionalOnlyNames,
760
+ requiredPosCount,
761
+ indent: ' ',
762
+ errorLabel: method.name,
763
+ };
764
+ const callPreludeLines = emitCallPrelude(callDescriptor, this.callEmitHelpers());
856
765
  const callPrelude = callPreludeLines.length > 0 ? `${callPreludeLines.join('\n')}\n` : '';
857
766
 
858
- const guardLines: string[] = [];
859
- if (needsKwargsParam && positionalOnlyNames.length > 0) {
860
- guardLines.push(
861
- ` const __positionalOnly = ${JSON.stringify(positionalOnlyNames)} as const;`
862
- );
863
- guardLines.push(` for (const key of __positionalOnly) {`);
864
- guardLines.push(
865
- ` if (__kwargs && Object.prototype.hasOwnProperty.call(__kwargs, key)) {`
866
- );
867
- guardLines.push(
868
- ` throw new Error(\`${method.name} does not accept positional-only argument "\${key}" as a keyword argument\`);`
869
- );
870
- guardLines.push(` }`);
871
- guardLines.push(` }`);
872
- }
873
- if (needsKwargsParam && requiredKwOnlyNames.length > 0) {
874
- guardLines.push(
875
- ` const __requiredKwOnly = ${JSON.stringify(requiredKwOnlyNames)} as const;`
876
- );
877
- guardLines.push(` const __missing: string[] = [];`);
878
- guardLines.push(` for (const key of __requiredKwOnly) {`);
879
- guardLines.push(
880
- ` if (!__kwargs || !Object.prototype.hasOwnProperty.call(__kwargs, key)) {`
881
- );
882
- guardLines.push(` __missing.push(key);`);
883
- guardLines.push(` }`);
884
- guardLines.push(` }`);
885
- guardLines.push(` if (__missing.length > 0) {`);
886
- guardLines.push(
887
- ` throw new Error(\`Missing required keyword-only arguments for ${method.name}: \${__missing.join(', ')}\`);`
888
- );
889
- guardLines.push(` }`);
890
- }
767
+ const guardLines = emitArgGuards(callDescriptor);
891
768
  const guards = guardLines.length > 0 ? `${guardLines.join('\n')}\n` : '';
892
769
 
893
770
  methodBodies.push(`${overloadDecl} async ${mname}${methodTypeParamDecl}(${paramsDecl}): Promise<${returnType}> {
@@ -994,95 +871,22 @@ ${callPrelude}${guards} return getRuntimeBridge().callMethod(this.__handle, '
994
871
  ? overloadDecl
995
872
  : ` static create${classTypeParamDecl}(${paramsDecl}): Promise<${classSelfType}>;\n`;
996
873
 
997
- const guardLines: string[] = [];
998
- const callPreludeLines: string[] = [];
999
- if (needsKwargsParam) {
1000
- callPreludeLines.push(` let __kwargs = kwargs;`);
1001
- }
1002
- const positionalArgExprs = positionalParams.map(p => this.escapeIdentifier(p.name));
1003
- callPreludeLines.push(` const __args: unknown[] = [${positionalArgExprs.join(', ')}];`);
1004
- if (requiredPosCount < positionalParams.length) {
1005
- callPreludeLines.push(
1006
- ` while (__args.length > ${requiredPosCount} && __args[__args.length - 1] === undefined) {`
1007
- );
1008
- callPreludeLines.push(` __args.pop();`);
1009
- callPreludeLines.push(` }`);
1010
- }
1011
- if (needsKwargsParam && requiredPosCount < positionalParams.length) {
1012
- const looksLikeKwargs = this.renderLooksLikeKwargsExpr('__candidate', {
1013
- keywordOnlyNames,
1014
- requiredKwOnlyNames,
1015
- hasVarKwArgs,
1016
- });
1017
- callPreludeLines.push(
1018
- ` if (__kwargs === undefined && __args.length > ${requiredPosCount}) {`
1019
- );
1020
- callPreludeLines.push(` const __candidate = __args[__args.length - 1];`);
1021
- callPreludeLines.push(` if (${looksLikeKwargs}) {`);
1022
- callPreludeLines.push(` __kwargs = __candidate as any;`);
1023
- callPreludeLines.push(` __args.pop();`);
1024
- callPreludeLines.push(` }`);
1025
- callPreludeLines.push(` }`);
1026
- }
1027
- if (varArgsParam) {
1028
- const vname = this.escapeIdentifier(varArgsParam.name);
1029
- if (needsVarArgsArray) {
1030
- const looksLikeKwargs = this.renderLooksLikeKwargsExpr(vname, {
1031
- keywordOnlyNames,
1032
- requiredKwOnlyNames,
1033
- hasVarKwArgs,
1034
- });
1035
- callPreludeLines.push(` let __varargs: unknown[] = [];`);
1036
- callPreludeLines.push(` if (${vname} !== undefined) {`);
1037
- callPreludeLines.push(` if (globalThis.Array.isArray(${vname})) {`);
1038
- callPreludeLines.push(` __varargs = ${vname};`);
1039
- callPreludeLines.push(` } else if (__kwargs === undefined && ${looksLikeKwargs}) {`);
1040
- callPreludeLines.push(` __kwargs = ${vname} as any;`);
1041
- callPreludeLines.push(` } else {`);
1042
- callPreludeLines.push(
1043
- ` throw new Error(\`__init__ expected ${varArgsParam.name} to be an array\`);`
1044
- );
1045
- callPreludeLines.push(` }`);
1046
- callPreludeLines.push(` }`);
1047
- callPreludeLines.push(` __args.push(...__varargs);`);
1048
- } else {
1049
- callPreludeLines.push(` __args.push(...${vname});`);
1050
- }
1051
- }
874
+ const callDescriptor: CallDescriptor = {
875
+ positionalParams,
876
+ varArgsParam,
877
+ needsVarArgsArray,
878
+ hasKwArgs: needsKwargsParam,
879
+ hasVarKwArgs,
880
+ keywordOnlyNames,
881
+ requiredKwOnlyNames,
882
+ positionalOnlyNames,
883
+ requiredPosCount,
884
+ indent: ' ',
885
+ errorLabel: '__init__',
886
+ };
887
+ const callPreludeLines = emitCallPrelude(callDescriptor, this.callEmitHelpers());
1052
888
  const callPrelude = callPreludeLines.length > 0 ? `${callPreludeLines.join('\n')}\n` : '';
1053
-
1054
- if (needsKwargsParam && positionalOnlyNames.length > 0) {
1055
- guardLines.push(
1056
- ` const __positionalOnly = ${JSON.stringify(positionalOnlyNames)} as const;`
1057
- );
1058
- guardLines.push(` for (const key of __positionalOnly) {`);
1059
- guardLines.push(
1060
- ` if (__kwargs && Object.prototype.hasOwnProperty.call(__kwargs, key)) {`
1061
- );
1062
- guardLines.push(
1063
- ` throw new Error(\`__init__ does not accept positional-only argument "\${key}" as a keyword argument\`);`
1064
- );
1065
- guardLines.push(` }`);
1066
- guardLines.push(` }`);
1067
- }
1068
- if (needsKwargsParam && requiredKwOnlyNames.length > 0) {
1069
- guardLines.push(
1070
- ` const __requiredKwOnly = ${JSON.stringify(requiredKwOnlyNames)} as const;`
1071
- );
1072
- guardLines.push(` const __missing: string[] = [];`);
1073
- guardLines.push(` for (const key of __requiredKwOnly) {`);
1074
- guardLines.push(
1075
- ` if (!__kwargs || !Object.prototype.hasOwnProperty.call(__kwargs, key)) {`
1076
- );
1077
- guardLines.push(` __missing.push(key);`);
1078
- guardLines.push(` }`);
1079
- guardLines.push(` }`);
1080
- guardLines.push(` if (__missing.length > 0) {`);
1081
- guardLines.push(
1082
- ` throw new Error(\`Missing required keyword-only arguments for __init__: \${__missing.join(', ')}\`);`
1083
- );
1084
- guardLines.push(` }`);
1085
- }
889
+ const guardLines = emitArgGuards(callDescriptor);
1086
890
 
1087
891
  return {
1088
892
  overloadDecl,