@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.
- package/LICENSE +201 -0
- package/README.i18n.yaml +6 -0
- package/README.md +209 -0
- package/README.zh.md +200 -0
- package/lib/abort-utils.d.ts +80 -0
- package/lib/abort-utils.d.ts.map +1 -0
- package/lib/abort-utils.js +186 -0
- package/lib/abort-utils.js.map +1 -0
- package/lib/cc-names.d.ts +100 -0
- package/lib/cc-names.d.ts.map +1 -0
- package/lib/cc-names.js +197 -0
- package/lib/cc-names.js.map +1 -0
- package/lib/code-mode.d.ts +46 -0
- package/lib/code-mode.d.ts.map +1 -0
- package/lib/code-mode.js +380 -0
- package/lib/code-mode.js.map +1 -0
- package/lib/define-tool.d.ts +103 -0
- package/lib/define-tool.d.ts.map +1 -0
- package/lib/define-tool.js +354 -0
- package/lib/define-tool.js.map +1 -0
- package/lib/index.d.ts +348 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +289 -0
- package/lib/index.js.map +1 -0
- package/lib/invariant.d.ts +13 -0
- package/lib/invariant.d.ts.map +1 -0
- package/lib/invariant.js +123 -0
- package/lib/invariant.js.map +1 -0
- package/lib/json-render.d.ts +18 -0
- package/lib/json-render.d.ts.map +1 -0
- package/lib/json-render.js +111 -0
- package/lib/json-render.js.map +1 -0
- package/lib/json-schema-value.d.ts +18 -0
- package/lib/json-schema-value.d.ts.map +1 -0
- package/lib/json-schema-value.js +238 -0
- package/lib/json-schema-value.js.map +1 -0
- package/lib/json-schema.d.ts +101 -0
- package/lib/json-schema.d.ts.map +1 -0
- package/lib/json-schema.js +351 -0
- package/lib/json-schema.js.map +1 -0
- package/lib/presentation.d.ts +367 -0
- package/lib/presentation.d.ts.map +1 -0
- package/lib/presentation.js +8 -0
- package/lib/presentation.js.map +1 -0
- package/lib/py-names.d.ts +163 -0
- package/lib/py-names.d.ts.map +1 -0
- package/lib/py-names.js +236 -0
- package/lib/py-names.js.map +1 -0
- package/lib/py-render.d.ts +23 -0
- package/lib/py-render.d.ts.map +1 -0
- package/lib/py-render.js +434 -0
- package/lib/py-render.js.map +1 -0
- package/lib/py-sdk-doc.d.ts +29 -0
- package/lib/py-sdk-doc.d.ts.map +1 -0
- package/lib/py-sdk-doc.js +114 -0
- package/lib/py-sdk-doc.js.map +1 -0
- package/lib/py-types.d.ts +34 -0
- package/lib/py-types.d.ts.map +1 -0
- package/lib/py-types.js +40 -0
- package/lib/py-types.js.map +1 -0
- package/lib/run-code-defs.d.ts +77 -0
- package/lib/run-code-defs.d.ts.map +1 -0
- package/lib/run-code-defs.js +98 -0
- package/lib/run-code-defs.js.map +1 -0
- package/lib/runtime-code.d.ts +65 -0
- package/lib/runtime-code.d.ts.map +1 -0
- package/lib/runtime-code.js +129 -0
- package/lib/runtime-code.js.map +1 -0
- package/lib/runtime-core.d.ts +130 -0
- package/lib/runtime-core.d.ts.map +1 -0
- package/lib/runtime-core.js +33 -0
- package/lib/runtime-core.js.map +1 -0
- package/lib/runtime-execute.d.ts +82 -0
- package/lib/runtime-execute.d.ts.map +1 -0
- package/lib/runtime-execute.js +333 -0
- package/lib/runtime-execute.js.map +1 -0
- package/lib/runtime-registry.d.ts +131 -0
- package/lib/runtime-registry.d.ts.map +1 -0
- package/lib/runtime-registry.js +269 -0
- package/lib/runtime-registry.js.map +1 -0
- package/lib/runtime-results.d.ts +32 -0
- package/lib/runtime-results.d.ts.map +1 -0
- package/lib/runtime-results.js +163 -0
- package/lib/runtime-results.js.map +1 -0
- package/lib/runtime-schemas.d.ts +112 -0
- package/lib/runtime-schemas.d.ts.map +1 -0
- package/lib/runtime-schemas.js +222 -0
- package/lib/runtime-schemas.js.map +1 -0
- package/lib/scheduler.d.ts +22 -0
- package/lib/scheduler.d.ts.map +1 -0
- package/lib/scheduler.js +21 -0
- package/lib/scheduler.js.map +1 -0
- package/lib/schema-spec.d.ts +154 -0
- package/lib/schema-spec.d.ts.map +1 -0
- package/lib/schema-spec.js +9 -0
- package/lib/schema-spec.js.map +1 -0
- package/lib/schema.d.ts +5 -0
- package/lib/schema.d.ts.map +1 -0
- package/lib/schema.js +3 -0
- package/lib/schema.js.map +1 -0
- package/lib/testing.d.ts +25 -0
- package/lib/testing.d.ts.map +1 -0
- package/lib/testing.js +25 -0
- package/lib/testing.js.map +1 -0
- package/lib/tool-layer.d.ts +49 -0
- package/lib/tool-layer.d.ts.map +1 -0
- package/lib/tool-layer.js +57 -0
- package/lib/tool-layer.js.map +1 -0
- package/lib/tool-types.d.ts +385 -0
- package/lib/tool-types.d.ts.map +1 -0
- package/lib/tool-types.js +11 -0
- package/lib/tool-types.js.map +1 -0
- package/lib/ts-types.d.ts +37 -0
- package/lib/ts-types.d.ts.map +1 -0
- package/lib/ts-types.js +265 -0
- package/lib/ts-types.js.map +1 -0
- package/lib/types.d.ts +55 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +7 -0
- package/lib/types.js.map +1 -0
- package/package.json +65 -0
package/lib/py-names.js
ADDED
|
@@ -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":"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"}
|
|
@@ -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"}
|