@dsh-cc/tools 0.5.0

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 (121) hide show
  1. package/LICENSE +201 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +209 -0
  4. package/README.zh.md +200 -0
  5. package/lib/abort-utils.d.ts +80 -0
  6. package/lib/abort-utils.d.ts.map +1 -0
  7. package/lib/abort-utils.js +186 -0
  8. package/lib/abort-utils.js.map +1 -0
  9. package/lib/cc-names.d.ts +100 -0
  10. package/lib/cc-names.d.ts.map +1 -0
  11. package/lib/cc-names.js +197 -0
  12. package/lib/cc-names.js.map +1 -0
  13. package/lib/code-mode.d.ts +46 -0
  14. package/lib/code-mode.d.ts.map +1 -0
  15. package/lib/code-mode.js +380 -0
  16. package/lib/code-mode.js.map +1 -0
  17. package/lib/define-tool.d.ts +103 -0
  18. package/lib/define-tool.d.ts.map +1 -0
  19. package/lib/define-tool.js +354 -0
  20. package/lib/define-tool.js.map +1 -0
  21. package/lib/index.d.ts +348 -0
  22. package/lib/index.d.ts.map +1 -0
  23. package/lib/index.js +289 -0
  24. package/lib/index.js.map +1 -0
  25. package/lib/invariant.d.ts +13 -0
  26. package/lib/invariant.d.ts.map +1 -0
  27. package/lib/invariant.js +123 -0
  28. package/lib/invariant.js.map +1 -0
  29. package/lib/json-render.d.ts +18 -0
  30. package/lib/json-render.d.ts.map +1 -0
  31. package/lib/json-render.js +111 -0
  32. package/lib/json-render.js.map +1 -0
  33. package/lib/json-schema-value.d.ts +18 -0
  34. package/lib/json-schema-value.d.ts.map +1 -0
  35. package/lib/json-schema-value.js +238 -0
  36. package/lib/json-schema-value.js.map +1 -0
  37. package/lib/json-schema.d.ts +101 -0
  38. package/lib/json-schema.d.ts.map +1 -0
  39. package/lib/json-schema.js +351 -0
  40. package/lib/json-schema.js.map +1 -0
  41. package/lib/presentation.d.ts +367 -0
  42. package/lib/presentation.d.ts.map +1 -0
  43. package/lib/presentation.js +8 -0
  44. package/lib/presentation.js.map +1 -0
  45. package/lib/py-names.d.ts +163 -0
  46. package/lib/py-names.d.ts.map +1 -0
  47. package/lib/py-names.js +236 -0
  48. package/lib/py-names.js.map +1 -0
  49. package/lib/py-render.d.ts +23 -0
  50. package/lib/py-render.d.ts.map +1 -0
  51. package/lib/py-render.js +434 -0
  52. package/lib/py-render.js.map +1 -0
  53. package/lib/py-sdk-doc.d.ts +29 -0
  54. package/lib/py-sdk-doc.d.ts.map +1 -0
  55. package/lib/py-sdk-doc.js +114 -0
  56. package/lib/py-sdk-doc.js.map +1 -0
  57. package/lib/py-types.d.ts +34 -0
  58. package/lib/py-types.d.ts.map +1 -0
  59. package/lib/py-types.js +40 -0
  60. package/lib/py-types.js.map +1 -0
  61. package/lib/run-code-defs.d.ts +77 -0
  62. package/lib/run-code-defs.d.ts.map +1 -0
  63. package/lib/run-code-defs.js +98 -0
  64. package/lib/run-code-defs.js.map +1 -0
  65. package/lib/runtime-code.d.ts +65 -0
  66. package/lib/runtime-code.d.ts.map +1 -0
  67. package/lib/runtime-code.js +129 -0
  68. package/lib/runtime-code.js.map +1 -0
  69. package/lib/runtime-core.d.ts +130 -0
  70. package/lib/runtime-core.d.ts.map +1 -0
  71. package/lib/runtime-core.js +33 -0
  72. package/lib/runtime-core.js.map +1 -0
  73. package/lib/runtime-execute.d.ts +82 -0
  74. package/lib/runtime-execute.d.ts.map +1 -0
  75. package/lib/runtime-execute.js +333 -0
  76. package/lib/runtime-execute.js.map +1 -0
  77. package/lib/runtime-registry.d.ts +131 -0
  78. package/lib/runtime-registry.d.ts.map +1 -0
  79. package/lib/runtime-registry.js +269 -0
  80. package/lib/runtime-registry.js.map +1 -0
  81. package/lib/runtime-results.d.ts +32 -0
  82. package/lib/runtime-results.d.ts.map +1 -0
  83. package/lib/runtime-results.js +163 -0
  84. package/lib/runtime-results.js.map +1 -0
  85. package/lib/runtime-schemas.d.ts +112 -0
  86. package/lib/runtime-schemas.d.ts.map +1 -0
  87. package/lib/runtime-schemas.js +222 -0
  88. package/lib/runtime-schemas.js.map +1 -0
  89. package/lib/scheduler.d.ts +22 -0
  90. package/lib/scheduler.d.ts.map +1 -0
  91. package/lib/scheduler.js +21 -0
  92. package/lib/scheduler.js.map +1 -0
  93. package/lib/schema-spec.d.ts +154 -0
  94. package/lib/schema-spec.d.ts.map +1 -0
  95. package/lib/schema-spec.js +9 -0
  96. package/lib/schema-spec.js.map +1 -0
  97. package/lib/schema.d.ts +5 -0
  98. package/lib/schema.d.ts.map +1 -0
  99. package/lib/schema.js +3 -0
  100. package/lib/schema.js.map +1 -0
  101. package/lib/testing.d.ts +25 -0
  102. package/lib/testing.d.ts.map +1 -0
  103. package/lib/testing.js +25 -0
  104. package/lib/testing.js.map +1 -0
  105. package/lib/tool-layer.d.ts +49 -0
  106. package/lib/tool-layer.d.ts.map +1 -0
  107. package/lib/tool-layer.js +57 -0
  108. package/lib/tool-layer.js.map +1 -0
  109. package/lib/tool-types.d.ts +385 -0
  110. package/lib/tool-types.d.ts.map +1 -0
  111. package/lib/tool-types.js +11 -0
  112. package/lib/tool-types.js.map +1 -0
  113. package/lib/ts-types.d.ts +37 -0
  114. package/lib/ts-types.d.ts.map +1 -0
  115. package/lib/ts-types.js +265 -0
  116. package/lib/ts-types.js.map +1 -0
  117. package/lib/types.d.ts +55 -0
  118. package/lib/types.d.ts.map +1 -0
  119. package/lib/types.js +7 -0
  120. package/lib/types.js.map +1 -0
  121. package/package.json +65 -0
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Naming, state, and text-escaping machinery shared by the Python SDK renderers
3
+ * (`py-types.ts`, `py-render.ts`, `py-sdk-doc.ts`). Leaf module: imports nothing
4
+ * from its siblings, so any of them may depend on it without creating cycles.
5
+ * Split out of `py-types.ts` for the line budget.
6
+ * @module @dsh-cc/tools/src/py-names
7
+ */
8
+ /**
9
+ * The reference grammar's `xid_start xid_continue*` — the set
10
+ * `str.isidentifier()` accepts on a CPython whose Unicode tables match the
11
+ * engine's. See {@link isBareIdentifier} for what a version skew does.
12
+ */
13
+ const IDENTIFIER = /^[\p{XID_Start}_]\p{XID_Continue}*$/u;
14
+ /**
15
+ * Whether a name can be emitted as a bare Python identifier rather than
16
+ * routed to the subscript/`dict[str, Any]` path.
17
+ *
18
+ * Python identifiers are not ASCII: `路径` is as legal a field name as `path`,
19
+ * and rejecting it would degrade the whole enclosing object, dropping every
20
+ * field's name, requiredness, and type — information whose only source under
21
+ * `mode: 'code'` is this generated text.
22
+ *
23
+ * NFKC stability is a second and separate condition, because CPython
24
+ * normalizes identifiers at compile time while JSON keys are compared as
25
+ * written: `field` would be declared and reachable as `field`, so the SDK would
26
+ * advertise a key under a spelling the harness never accepts, and two keys
27
+ * that normalize together would collapse into one declaration. Those names
28
+ * take the subscript path, which carries their exact bytes.
29
+ *
30
+ * `IDENTIFIER` matches `str.isidentifier()` (measured on Node 22.23.1 vs
31
+ * CPython 3.9.6 tables): the equivalence holds inside the two versions' shared
32
+ * tables, and the skew characters below are exactly where that pair diverges.
33
+ * The predicate as a whole is deliberately stricter than `isidentifier()`,
34
+ * which does not test NFKC stability: `'field'.isidentifier()` is True and
35
+ * this returns false.
36
+ *
37
+ * Both conditions are evaluated against the ENGINE's Unicode tables, and the
38
+ * two sides are versioned independently — `\p{XID_Start}`/`\p{XID_Continue}`
39
+ * follow the running engine (Node 22.23.1 reports Unicode 17.0) while CPython
40
+ * follows its own (3.9.6 reports 13.0.0). The skew is not symmetric. A CPython
41
+ * older than the engine is the dangerous direction: a character added to either
42
+ * property since its tables (U+10570 Vithkuqi and U+1E290 Toto, 14.0; U+1E4D0
43
+ * Nag Mundari, 15.0; U+1C89 Cyrillic TJE, 16.0 — ages per `DerivedAge.txt`; all
44
+ * four are NFKC-stable and accepted here, and all four are `Cn` on that 3.9.6,
45
+ * which rejects them) is emitted bare and its tokenizer refuses the character,
46
+ * taking the whole SDK block down — the same parseability invariant
47
+ * {@link UNPRINTABLE}, {@link LONE_SURROGATE} and {@link MAX_LIST_NESTING}
48
+ * exist for. Both properties carry it: a character added only to `XID_Continue`
49
+ * passes the trailing `\p{XID_Continue}*` in a tail position and fails the same
50
+ * way — U+200C ZWNJ and U+200D ZWJ are that case, gaining `XID_Continue` in UCD
51
+ * 15.1 and absent from it in 13.0.0, 14.0.0 and 15.0.0, so `a\u{200C}b` is
52
+ * emitted bare here while `isidentifier()` is False on 3.9.6 and on 3.12.13
53
+ * (15.0.0). A CPython newer than the engine only routes a legal name to the
54
+ * subscript/`dict[str, Any]` path: less readable, still correct. The NFKC
55
+ * condition reduces to the same skew, since normalization stability guarantees
56
+ * an assigned character's normalization never changes afterwards.
57
+ *
58
+ * This predicate is not the only reader of engine tables. {@link camelCase}
59
+ * reads them at three further points — its split set, its head test, and its
60
+ * `toUpperCase()` case mapping — and this predicate's verdict gates none of
61
+ * them: a class name derived there reaches emitted text whenever any object
62
+ * shape in the tool's schema declares a `TypedDict`, including for a tool this
63
+ * predicate rejected. A tool named `zz-\u{1E4D0}x` with such parameters never
64
+ * reaches the skew here (the `-` rejects it outright) yet emits `class
65
+ * Zz\u{1E4D0}xArgs`, which that same 3.9.6 refuses — Nag Mundari arrived two
66
+ * releases after its tables. The case mapping is a separate table rather than
67
+ * an XID membership test, and it fails on names both conditions above accept:
68
+ * `\u{019B}` is XID_Start and NFKC-stable, so this predicate accepts it and
69
+ * `async def \u{019B}` compiles on 3.9.6, but Node uppercases it to
70
+ * `\u{A7DC}` — unassigned in that CPython, whose own `.upper()` is the identity
71
+ * here — and the declared `class \u{A7DC}Args` fails with `invalid
72
+ * non-printable character U+A7DC`. Closing the exposure therefore covers all
73
+ * four read points, not this predicate alone; it needs the target interpreter's
74
+ * version, which the backend reporting `language: 'python'` owns; the
75
+ * language-dispatch Agent Note records the deferral.
76
+ *
77
+ * The `ts-types` sibling keeps its own ASCII rule rather than sharing this
78
+ * one: ECMAScript identifiers are a different set (`$`) and are never
79
+ * normalized, so one predicate cannot be correct for both. ZWJ/ZWNJ are not
80
+ * part of that difference — both sets carry them on the engine's tables; what
81
+ * separates the two there is the CPython table version above.
82
+ * @param name - the raw schema field or tool name.
83
+ * @returns whether the name can be emitted bare.
84
+ */
85
+ export function isBareIdentifier(name) {
86
+ return IDENTIFIER.test(name) && name.normalize('NFKC') === name;
87
+ }
88
+ /**
89
+ * Python hard keywords: reserved everywhere, so a tool or field named
90
+ * ``class`` or ``lambda`` is legal on the wire but not as an attribute
91
+ * (``tools.class`` would be a SyntaxError in the model program) and not as a
92
+ * class-syntax `TypedDict` field. Such a tool renders under subscript access
93
+ * and such an object degrades to ``dict[str, Any]`` — the model still reaches
94
+ * every tool and field without collisions.
95
+ * Soft keywords (``match``, ``case``, ``type``, ``_`` — the language
96
+ * reference's whole set) are deliberately ABSENT: each is special in exactly
97
+ * one syntactic position — a statement head (``match``, ``type``), a ``match``
98
+ * statement's clause head (``case``), or a pattern (``_``) — so ``match: str``
99
+ * as a field and ``async def match(...)`` as a method are both legal, and
100
+ * including them would needlessly degrade common search/regex tool fields to
101
+ * ``dict[str, Any]``. Underscore-leading names are handled separately, not
102
+ * here: a non-dunder ``__token`` name-mangles, a dunder present on
103
+ * ``object``/``type`` resolves before the proxy hook, and implicit
104
+ * special-method lookup bypasses the hook.
105
+ */
106
+ export const RESERVED = new Set([
107
+ 'False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class',
108
+ 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global',
109
+ 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise',
110
+ 'return', 'try', 'while', 'with', 'yield',
111
+ // Not a keyword, but CPython refuses to ASSIGN it at compile time
112
+ // (`SyntaxError: cannot assign to __debug__`), which is what a TypedDict
113
+ // field, a parameter name, and a keyword argument all are.
114
+ '__debug__',
115
+ ]);
116
+ /** `indent`-deep line prefix (four spaces per level to match PEP 8 output). */
117
+ export function pad(indent) {
118
+ return ' '.repeat(indent);
119
+ }
120
+ /**
121
+ * The `Cc` code points that survive the whitespace collapse in {@link describe}
122
+ * and have no printable form: the C0 controls, DEL, and the C1 controls. Only
123
+ * U+0009 to U+000D are absent, because ECMAScript `\s` already collapsed them —
124
+ * `\s` is TAB/VT/FF/SP/NBSP/ZWNBSP/Zs plus LF/CR/LS/PS, so no C1 code point is
125
+ * in it and the whole U+0080 to U+009F block reaches this rule intact. Those
126
+ * are not hypothetical input: they are what Windows-1252 bytes 0x80 to 0x9F
127
+ * (smart quotes, em dash) become when decoded as Latin-1.
128
+ * CPython rejects source containing a NUL outright
129
+ * (`SyntaxError: source code string cannot contain null bytes`), whether it
130
+ * sits in a docstring or in a comment, so one such byte anywhere in a schema
131
+ * description would make the whole generated SDK unparseable — under
132
+ * `mode: 'code'`, the model's only declaration of the tools. The rest are
133
+ * legal but invisible; escaping them with the same rule keeps the emitted text
134
+ * readable and the treatment uniform.
135
+ *
136
+ * The boundary is the category, not per-code-point addressability: `\xNN`
137
+ * addresses U+0000 to U+00FF, so one escape form covers `Cc` exactly. The
138
+ * invisible `Cf` formatting characters pass through by design — of them only
139
+ * U+00AD soft hyphen would fit `\xNN` at all, and escaping that one while
140
+ * U+200B ZWSP, U+200E/U+200F bidi marks, and U+2060 word joiner passed through
141
+ * would leave a rule that is neither category- nor addressability-shaped. The
142
+ * whole family is legal in both consumers, since only LF and CR terminate a
143
+ * Python string literal or a `#` comment. That set is the tokenizer's, not
144
+ * `str.splitlines()`': NEL (U+0085), LS (U+2028), and PS (U+2029) split a
145
+ * string at run time but do not end a physical line in source — measured on
146
+ * CPython 3.9.6 and 3.12.13, each accepted in both positions with the value
147
+ * round-tripping — so they are safe raw wherever they reach emitted text
148
+ * unescaped, which for all three is `JSON.stringify`, at two call sites:
149
+ * the scalar literal path, and the subscript tool-name comment's own
150
+ * call, which a name carrying any of them always reaches, none being
151
+ * `XID_Continue`. The `description` path escapes NEL under the class above and
152
+ * folds LS and PS in {@link describe}'s `\s+` collapse, both being `\s`.
153
+ */
154
+ const UNPRINTABLE = /[\u0000-\u0008\u000e-\u001f\u007f-\u009f]/g;
155
+ /**
156
+ * Unpaired surrogate code points, escaped by {@link describe} as `\uNNNN` —
157
+ * its own form, since `\xNN` stops at U+00FF. The `u` flag is what makes this
158
+ * the LONE ones: in Unicode mode a well-formed pair is a single astral code
159
+ * point outside D800 to DFFF, so an emoji in a description survives untouched.
160
+ *
161
+ * This is the NUL case from {@link UNPRINTABLE}, not the invisible-character
162
+ * case. Python source must be UTF-8-encodable and a lone surrogate is not, so
163
+ * `compile()` raises `UnicodeEncodeError: surrogates not allowed` for one
164
+ * anywhere in the text — measured on 3.9 for a string literal and for a `#`
165
+ * comment alike. A raw or MCP tool description reaches this: `JSON.parse` on a
166
+ * wire `"\ud800"` escape yields exactly such a code point.
167
+ */
168
+ const LONE_SURROGATE = /[\ud800-\udfff]/gu;
169
+ /**
170
+ * The collapsed one-line `description` of a schema node (byte-stable across
171
+ * formatting churn), or `undefined` when the node carries none. Every caller
172
+ * passes an object — a validated property node, the `ToolSdkSchema` itself, or
173
+ * the `{ description }` wrapper {@link docLines} synthesizes — so only the
174
+ * description field needs guarding. A description that collapses
175
+ * to nothing (empty, or whitespace only) is `undefined` too: it documents the
176
+ * node no better than an absent one, and emitting it would leave an empty
177
+ * `"""` docstring or a bare `# ` line in the SDK. Only ECMAScript whitespace
178
+ * folds, so a description of whitespace plus one surviving control character is
179
+ * NOT absent: it collapses to that character's visible escape.
180
+ *
181
+ * Control characters left over after the whitespace collapse are rendered as
182
+ * their `\xNN` escapes (see {@link UNPRINTABLE}) and unpaired surrogates as
183
+ * their `\uNNNN` escapes (see {@link LONE_SURROGATE}); the escape's own backslash is
184
+ * emitted literally by both consumers, since {@link docLines} doubles it into a
185
+ * Python source escape and a `#` comment carries it verbatim.
186
+ */
187
+ export function describe(schema) {
188
+ const description = schema.description;
189
+ if (typeof description !== 'string')
190
+ return undefined;
191
+ const collapsed = description
192
+ .replace(/\s+/g, ' ')
193
+ .replace(UNPRINTABLE, char => `\\x${char.charCodeAt(0).toString(16).padStart(2, '0')}`)
194
+ .replace(LONE_SURROGATE, char => `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`)
195
+ .trim();
196
+ return collapsed.length === 0 ? undefined : collapsed;
197
+ }
198
+ /**
199
+ * CamelCase a name into a Python type identifier: non-identifier characters
200
+ * split words, `_` splits too (it is `XID_Continue`, so the split set names it
201
+ * explicitly), and a head that cannot start an identifier takes a `Tool`
202
+ * prefix. Unicode survives, so a `路径` field yields `路径`-based class names
203
+ * instead of collapsing to the bare prefix. A character that is not
204
+ * `XID_Continue` splits even when it is a letter, so a name whose NFKC folding
205
+ * would leave the identifier set is not carried through — the split set is the
206
+ * grammar's, not an ASCII approximation of it.
207
+ *
208
+ * The result is NFKC-normalized: these names are generated, never matched
209
+ * against a JSON key, so normalizing is free here and keeps what CPython
210
+ * compiles identical to what is emitted — unlike {@link isBareIdentifier},
211
+ * which must reject unstable names outright. Normalizing AFTER the prefix
212
+ * decision is what makes that hold at the seam the prefix creates: `Tool` +
213
+ * a combining-mark head composes there (`U+0301` gives `Tooĺ`, U+013A), so
214
+ * normalizing only the un-prefixed part would emit a name CPython compiles to
215
+ * a different symbol. The second call is idempotent on the un-prefixed arm.
216
+ *
217
+ * The split set, the head test, and `toUpperCase()` all read the engine's
218
+ * Unicode tables, so this function carries the same version skew
219
+ * {@link isBareIdentifier} documents, by paths independent of it: a class name
220
+ * derived here reaches emitted text whenever any object shape in the tool's
221
+ * schema declares a `TypedDict`, and the predicate's verdict on the tool name
222
+ * does not gate that. The case mapping is the one that can fail on a name the
223
+ * predicate accepted; the worked example is there.
224
+ * @param raw - the schema field or tool name to derive from.
225
+ * @returns a class-name segment safe to emit.
226
+ */
227
+ export function camelCase(raw) {
228
+ const joined = raw
229
+ .split(/[^\p{XID_Continue}]+|_+/u)
230
+ .filter(part => part.length > 0)
231
+ .map(part => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
232
+ .join('')
233
+ .normalize('NFKC');
234
+ return (/^\p{XID_Start}/u.test(joined) ? joined : `Tool${joined}`).normalize('NFKC');
235
+ }
236
+ //# sourceMappingURL=py-names.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"py-names.js","sourceRoot":"","sources":["../src/py-names.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;GAIG;AACH,MAAM,UAAU,GAAG,sCAAsC,CAAA;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAA;AACjE,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC;IAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IAClF,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ;IACtF,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO;IAC9E,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO;IACzC,kEAAkE;IAClE,yEAAyE;IACzE,2DAA2D;IAC3D,WAAW;CACZ,CAAC,CAAA;AAEF,+EAA+E;AAC/E,MAAM,UAAU,GAAG,CAAC,MAAc;IAChC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;AAC9B,CAAC;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,WAAW,GAAG,4CAA4C,CAAA;AAEhE;;;;;;;;;;;;GAYG;AACH,MAAM,cAAc,GAAG,mBAAmB,CAAA;AAE1C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,MAAM,WAAW,GAAI,MAAkC,CAAC,WAAW,CAAA;IACnE,IAAI,OAAO,WAAW,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IACrD,MAAM,SAAS,GAAG,WAAW;SAC1B,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;SACtF,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;SACzF,IAAI,EAAE,CAAA;IACT,OAAO,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;AACvD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,MAAM,GAAG,GAAG;SACf,KAAK,CAAC,0BAA0B,CAAC;SACjC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;SAC/B,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,IAAI,CAAC,EAAE,CAAC;SACR,SAAS,CAAC,MAAM,CAAC,CAAA;IACpB,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;AACtF,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The Python type-expression renderer: {@link renderType}, the explicit-stack
3
+ * walker that maps one validated JSON-Schema node to a Python type expression
4
+ * while threading a {@link RenderState} to collect the `TypedDict` class
5
+ * declarations and `typing` symbols a full render needs. Split out of
6
+ * `py-types.ts` for the line budget; `jsonSchemaToPy` and `renderToolsSdkPy`
7
+ * remain the public entries, re-exported from `py-types.ts`.
8
+ * @module @dsh-cc/tools/src/py-render
9
+ */
10
+ import type { RenderState } from './py-names.ts';
11
+ /**
12
+ * Map one JSON-Schema node to a Python type expression, threading `state` to
13
+ * collect the `TypedDict` declarations and `typing` symbols a full render
14
+ * needs. `className` is the name to give an object node with properties (and
15
+ * the prefix for its nested objects). Handles every unified schema construct —
16
+ * `oneOf` (→ `X | Y`), `const`/`enum` (→ `Literal[...]`), `integer` (→ `int`),
17
+ * `null` (→ `None`) — and degrades an unsupported or malformed schema to `Any`
18
+ * without throwing, the same trusted-after-validation stance as the sibling
19
+ * {@link ./ts-types.ts | ts-types} renderer. `jsonSchemaToPy` is the
20
+ * context-free entry point; this is the collecting core.
21
+ */
22
+ export declare function renderType(schema: unknown, className: string, state: RenderState): string;
23
+ //# sourceMappingURL=py-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"py-render.d.ts","sourceRoot":"","sources":["../src/py-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAwLhD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM,CAwOzF"}