ssc_codegen 0.34.0__tar.gz → 0.36.0__tar.gz
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.
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/PKG-INFO +2 -2
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/pyproject.toml +1 -1
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/rest.py +43 -23
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/runtime.py +14 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/visitor.py +14 -1
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/rest.py +61 -24
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/rest.py +58 -37
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/.gitignore +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/LICENSE +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/README.md +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/_logging.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/array.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/base.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/cast.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/control.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/extract.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/function.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/helpers.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/jsondef.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/module.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/predicate_containers.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/predicate_ops.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/regex.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/rest.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/selectors.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/string.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/struct.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/typedef.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/types.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/core/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/core/contexts.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/core/expressions.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/core/format.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/core/linter.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/core/module_handler.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/core/predicates.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/core/reader.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/core/rest_artifacts.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/core/struct_parser.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/core/type_checking.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/exceptions.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/explore.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/generation/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/generation/builder.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/generation/runtime.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/health.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/main.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/naming.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/parsers/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/parsers/curl.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/parsers/http.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/regex_utils.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/request_spec.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/http_libs/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/http_libs/base.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/http_libs/nethttp.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/literals.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/regex.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/http_libs/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/http_libs/axios.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/http_libs/base.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/http_libs/fetch.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/visitor.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/profile.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/base.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/bs4.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/lxml.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/parsel.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/slax.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/http_libs/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/http_libs/aiohttp.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/http_libs/base.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/http_libs/httpx.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/http_libs/requests.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/visitor.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/resolver.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/spec.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/traversal/__init__.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/traversal/context.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/traversal/utils.py +0 -0
- {ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/traversal/walker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: ssc_codegen
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.36.0
|
|
4
4
|
Summary: Python-dsl code converter to html parser for web scraping
|
|
5
5
|
Project-URL: Documentation, https://github.com/vypivshiy/selector_schema_codegen#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/vypivshiy/selector_schema_codegen/issues
|
|
@@ -185,9 +185,14 @@ def emit_method_fetch(
|
|
|
185
185
|
ctx: WalkContext,
|
|
186
186
|
http: GoHttpLibStrategy,
|
|
187
187
|
) -> list[str]:
|
|
188
|
-
"""Emit a Go
|
|
188
|
+
"""Emit a Go HTTP-entry function for HTML-parser structs with ``@request``.
|
|
189
189
|
|
|
190
|
-
Signature: ``func
|
|
190
|
+
Signature: ``func New<Struct><Method>(ctx, client, <phs>, opts ...) (*Name, error)``
|
|
191
|
+
|
|
192
|
+
Free function (not a receiver method) — semantically a sibling of
|
|
193
|
+
``New<Name>(input string)`` that fetches the input from HTTP instead.
|
|
194
|
+
Struct-name prefix guarantees uniqueness across schemas in the same
|
|
195
|
+
package (default ``New<Name>Fetch``; ``@request name=X`` → ``New<Name>X``).
|
|
191
196
|
|
|
192
197
|
Idiomatic Go: cancellation via ``context.Context``, async via ``go f(ctx)``
|
|
193
198
|
on caller side. Headers/body inlined (no ``sscReqOpts`` dependency).
|
|
@@ -198,7 +203,8 @@ def emit_method_fetch(
|
|
|
198
203
|
struct = node.parent
|
|
199
204
|
assert isinstance(struct, StructBase)
|
|
200
205
|
name = to_pascal_case(struct.name)
|
|
201
|
-
|
|
206
|
+
method_suffix = to_pascal_case(node.name) if node.name else "Fetch"
|
|
207
|
+
func_name = f"New{name}{method_suffix}"
|
|
202
208
|
ph_params = placeholder_params(spec)
|
|
203
209
|
url_expr = render_url(spec.url)
|
|
204
210
|
|
|
@@ -206,7 +212,7 @@ def emit_method_fetch(
|
|
|
206
212
|
i2 = i1 + ctx.indent_char
|
|
207
213
|
|
|
208
214
|
lines: list[str] = [
|
|
209
|
-
f"{i1}func {
|
|
215
|
+
f"{i1}func {func_name}(ctx context.Context, client {http.client_type}{ph_params}, opts ...sscReqOpt) (*{name}, error) {{",
|
|
210
216
|
f"{i2}req, err := http.NewRequestWithContext(ctx, {_go_str(spec.method)}, {url_expr}, nil)",
|
|
211
217
|
f"{i2}if err != nil {{",
|
|
212
218
|
f"{i2}\treturn nil, err",
|
|
@@ -233,6 +239,15 @@ def emit_method_fetch(
|
|
|
233
239
|
f"{i2}req.Body = io.NopCloser(strings.NewReader({body_expr}))"
|
|
234
240
|
)
|
|
235
241
|
|
|
242
|
+
# Apply per-call opts (user headers are additive).
|
|
243
|
+
lines.append(f"{i2}if len(opts) > 0 {{")
|
|
244
|
+
lines.append(f"{i2}\t_opts := &sscReqOpts{{}}")
|
|
245
|
+
lines.append(f"{i2}\tfor _, o := range opts {{ o(_opts) }}")
|
|
246
|
+
lines.append(f"{i2}\tfor _k, _vs := range _opts.Headers {{")
|
|
247
|
+
lines.append(f"{i2}\t\tfor _, _v := range _vs {{ req.Header.Add(_k, _v) }}")
|
|
248
|
+
lines.append(f"{i2}\t}}")
|
|
249
|
+
lines.append(f"{i2}}}")
|
|
250
|
+
|
|
236
251
|
# Execute.
|
|
237
252
|
lines.extend(
|
|
238
253
|
[
|
|
@@ -284,6 +299,7 @@ def emit_method_rest(
|
|
|
284
299
|
node: MethodRest,
|
|
285
300
|
ctx: WalkContext,
|
|
286
301
|
http: GoHttpLibStrategy,
|
|
302
|
+
rcv: str,
|
|
287
303
|
) -> list[str]:
|
|
288
304
|
"""Emit a Go REST method that calls sscRestCall.
|
|
289
305
|
|
|
@@ -291,6 +307,10 @@ def emit_method_rest(
|
|
|
291
307
|
- typed value → ``(*SchemaJson, error)`` or ``([]SchemaJson, error)``
|
|
292
308
|
- void → ``(struct{}, error)``
|
|
293
309
|
|
|
310
|
+
Receiver method on the (empty) marker struct — namespaced by type so
|
|
311
|
+
multiple REST structs in one package don't collide. Caller writes
|
|
312
|
+
``NewApiX().Fetch(client, opts...)`` (factory + receiver).
|
|
313
|
+
|
|
294
314
|
Errors propagate as typed structs: ``@error`` variants via matchers,
|
|
295
315
|
``*UnknownErr`` for unmatched HTTP >= 400, ``*TransportErr`` for network.
|
|
296
316
|
Caller uses ``errors.As`` to discriminate.
|
|
@@ -298,6 +318,7 @@ def emit_method_rest(
|
|
|
298
318
|
spec = node.http_request.with_renamed_placeholders(to_camel_case)
|
|
299
319
|
struct = node.parent
|
|
300
320
|
assert isinstance(struct, StructBase)
|
|
321
|
+
name = to_pascal_case(struct.name)
|
|
301
322
|
method_name = to_pascal_case(node.name) if node.name else "Fetch"
|
|
302
323
|
ph_params = placeholder_params(spec)
|
|
303
324
|
matchers_var = f"{to_snake_case(struct.name)}Matchers"
|
|
@@ -323,31 +344,30 @@ def emit_method_rest(
|
|
|
323
344
|
|
|
324
345
|
lines: list[str] = []
|
|
325
346
|
|
|
326
|
-
# Function signature.
|
|
347
|
+
# Function signature (receiver method on marker struct).
|
|
327
348
|
lines.append(
|
|
328
|
-
f"{i1}func {method_name}(client {http.client_type}{ph_params}) ({ret_type}, error) {{"
|
|
349
|
+
f"{i1}func ({rcv} {name}) {method_name}(client {http.client_type}{ph_params}, opts ...sscReqOpt) ({ret_type}, error) {{"
|
|
329
350
|
)
|
|
330
351
|
|
|
331
|
-
# Build opts.
|
|
332
|
-
opts_lines = _build_opts(spec, i2)
|
|
333
|
-
|
|
334
|
-
# Call sscRestCall — inline if nil, multi-line if struct literal.
|
|
335
|
-
# For void responses, use `_` since the body is discarded.
|
|
352
|
+
# Build _opts from DSL, apply per-call user opts, then call sscRestCall.
|
|
353
|
+
opts_lines = _build_opts(spec, i2 + "\t")
|
|
336
354
|
body_var = "_" if not node.response_schema else "body"
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
)
|
|
355
|
+
|
|
356
|
+
# Assign DSL opts to _opts variable.
|
|
357
|
+
if len(opts_lines) == 1 and opts_lines[0].strip() == "nil":
|
|
358
|
+
lines.append(f"{i2}_opts := &sscReqOpts{{}}")
|
|
342
359
|
else:
|
|
343
|
-
lines.append(
|
|
344
|
-
|
|
345
|
-
f"{_go_str(spec.method)}, {url_expr},"
|
|
346
|
-
)
|
|
347
|
-
lines.append(f"{opts_lines[0].strip()}")
|
|
348
|
-
for ol in opts_lines[1:-1]:
|
|
360
|
+
lines.append(f"{i2}_opts := {opts_lines[0].strip()}")
|
|
361
|
+
for ol in opts_lines[1:]:
|
|
349
362
|
lines.append(ol)
|
|
350
|
-
|
|
363
|
+
|
|
364
|
+
# Apply per-call opts (functional options).
|
|
365
|
+
lines.append(f"{i2}for _, o := range opts {{ o(_opts) }}")
|
|
366
|
+
|
|
367
|
+
lines.append(
|
|
368
|
+
f"{i2}{body_var}, err := sscRestCall(client, {matchers_var}, "
|
|
369
|
+
f"{_go_str(spec.method)}, {url_expr}, _opts)"
|
|
370
|
+
)
|
|
351
371
|
|
|
352
372
|
# Error propagation.
|
|
353
373
|
lines.append(f"{i2}if err != nil {{")
|
|
@@ -493,6 +493,20 @@ BASE_REST_RUNTIME: list[str] = [
|
|
|
493
493
|
"\tBody string",
|
|
494
494
|
"}",
|
|
495
495
|
"",
|
|
496
|
+
"// sscReqOpt is a functional option for per-call request overrides.",
|
|
497
|
+
"// Applied after DSL-specified opts; user headers are additive (shallow-merge).",
|
|
498
|
+
"type sscReqOpt func(*sscReqOpts)",
|
|
499
|
+
"",
|
|
500
|
+
"// WithHeader adds a per-call header value (additive — does not replace DSL headers).",
|
|
501
|
+
"func WithHeader(key, val string) sscReqOpt {",
|
|
502
|
+
"\treturn func(o *sscReqOpts) {",
|
|
503
|
+
"\t\tif o.Headers == nil {",
|
|
504
|
+
"\t\t\to.Headers = sscHeaders{}",
|
|
505
|
+
"\t\t}",
|
|
506
|
+
"\t\to.Headers[key] = append(o.Headers[key], val)",
|
|
507
|
+
"\t}",
|
|
508
|
+
"}",
|
|
509
|
+
"",
|
|
496
510
|
"type sscErrMatcher struct {",
|
|
497
511
|
"\tStatus int",
|
|
498
512
|
"\tCheck func([]byte) bool",
|
|
@@ -596,6 +596,12 @@ class GoVisitor(BaseWalker):
|
|
|
596
596
|
lines.append(f"type {name} struct {{")
|
|
597
597
|
lines.append("}")
|
|
598
598
|
lines.append("")
|
|
599
|
+
# Empty-struct factory: caller writes New<Name>().Method(...) —
|
|
600
|
+
# the struct is a pure namespace marker (no state), receiver
|
|
601
|
+
# methods namespaced by type avoid collisions across schemas in
|
|
602
|
+
# the same package.
|
|
603
|
+
lines.append(f"func New{name}() {name} {{ return {name}{{}} }}")
|
|
604
|
+
lines.append("")
|
|
599
605
|
for child in node.body:
|
|
600
606
|
lines.extend(self.walk(child, ctx))
|
|
601
607
|
return lines
|
|
@@ -1885,7 +1891,14 @@ class GoVisitor(BaseWalker):
|
|
|
1885
1891
|
if spec.body_kind == "form" and isinstance(spec.body, dict):
|
|
1886
1892
|
self._builder.require_import('"net/url"')
|
|
1887
1893
|
self._builder.require_import('"' + self._http.import_path + '"')
|
|
1888
|
-
|
|
1894
|
+
struct = node.parent
|
|
1895
|
+
name = (
|
|
1896
|
+
to_pascal_case(struct.name)
|
|
1897
|
+
if isinstance(struct, StructBase)
|
|
1898
|
+
else "X"
|
|
1899
|
+
)
|
|
1900
|
+
rcv = _receiver(name)
|
|
1901
|
+
return rest.emit_method_rest(node, ctx, self._http, rcv)
|
|
1889
1902
|
|
|
1890
1903
|
def visit_method_fetch(
|
|
1891
1904
|
self, node: MethodFetch, ctx: WalkContext
|
|
@@ -390,13 +390,28 @@ def emit_method_rest(
|
|
|
390
390
|
t = f"{t}[]"
|
|
391
391
|
bracket = f"[params.{p.name}]" if p.is_optional else f"params.{p.name}"
|
|
392
392
|
lines.append(f"{i1} * @param {{{t}}} {bracket}")
|
|
393
|
+
lines.append(
|
|
394
|
+
f"{i1} * @param {{Object}} [opts] per-call request options (headers, etc.)"
|
|
395
|
+
)
|
|
393
396
|
lines.append(f"{i1} * @returns {{Promise<{return_union}>}}")
|
|
394
397
|
lines.append(f"{i1} */")
|
|
395
|
-
lines.append(
|
|
398
|
+
lines.append(
|
|
399
|
+
f"{i1}static async {method_name}(client{ph_param}, opts = {{}}) {{"
|
|
400
|
+
)
|
|
396
401
|
lines.extend(pre_lines)
|
|
402
|
+
lines.append(f"{i2}const _kw = {opts_obj};")
|
|
403
|
+
lines.append(f"{i2}for (const [_k, _v] of Object.entries(opts)) {{")
|
|
404
|
+
lines.append(
|
|
405
|
+
f"{i2} if (typeof _kw[_k] === 'object' && _kw[_k] !== null && typeof _v === 'object' && _v !== null) {{"
|
|
406
|
+
)
|
|
407
|
+
lines.append(f"{i2} _kw[_k] = {{..._kw[_k], ..._v}};")
|
|
408
|
+
lines.append(f"{i2} }} else {{")
|
|
409
|
+
lines.append(f"{i2} _kw[_k] = _v;")
|
|
410
|
+
lines.append(f"{i2} }}")
|
|
411
|
+
lines.append(f"{i2}}}")
|
|
397
412
|
lines.append(
|
|
398
413
|
f"{i2}return {fn_name}(client, {matchers_var}, "
|
|
399
|
-
f"{spec.method!r}, {url_expr}, {value_fn},
|
|
414
|
+
f"{spec.method!r}, {url_expr}, {value_fn}, _kw);"
|
|
400
415
|
)
|
|
401
416
|
lines.append(f"{i1}}}")
|
|
402
417
|
return lines
|
|
@@ -434,9 +449,13 @@ def emit_method_fetch(
|
|
|
434
449
|
rl.append(f"{i2}return new {struct_name}(_body);")
|
|
435
450
|
return rl
|
|
436
451
|
|
|
437
|
-
lines: list[str] = [
|
|
452
|
+
lines: list[str] = [
|
|
453
|
+
f"{i1}static async {method_name}(client{ph_param}, opts = {{}}) {{"
|
|
454
|
+
]
|
|
438
455
|
lines.extend(pre_lines)
|
|
439
456
|
|
|
457
|
+
# Build _kw from DSL-specified request options (method/url stay out).
|
|
458
|
+
kw_parts: list[str] = []
|
|
440
459
|
if http_client == "fetch":
|
|
441
460
|
if params_expr:
|
|
442
461
|
url_inner = spec.url.map(
|
|
@@ -446,21 +465,32 @@ def emit_method_fetch(
|
|
|
446
465
|
url_expr = f"`{url_inner}?${{new URLSearchParams({params_expr})}}`"
|
|
447
466
|
else:
|
|
448
467
|
url_expr = render_value(spec.url)
|
|
449
|
-
options: list[str] = [f"{i3}method: {spec.method!r},"]
|
|
450
468
|
if headers_expr:
|
|
451
|
-
|
|
469
|
+
kw_parts.append(f"headers: {headers_expr}")
|
|
452
470
|
if spec.cookies:
|
|
453
471
|
cookie_str = "; ".join(
|
|
454
472
|
f"{k}={v.source}" for k, v in spec.cookies.items()
|
|
455
473
|
)
|
|
456
|
-
|
|
457
|
-
f"
|
|
474
|
+
kw_parts.append(
|
|
475
|
+
f"// cookies: {cookie_str!r} /* set via headers or credentials */"
|
|
458
476
|
)
|
|
459
477
|
if body_expr:
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
lines.
|
|
463
|
-
lines.append(f"{i2}
|
|
478
|
+
kw_parts.append(f"body: {body_expr}")
|
|
479
|
+
kw_obj = "{" + ", ".join(kw_parts) + "}" if kw_parts else "{}"
|
|
480
|
+
lines.append(f"{i2}const _kw = {kw_obj};")
|
|
481
|
+
lines.append(f"{i2}for (const [_k, _v] of Object.entries(opts)) {{")
|
|
482
|
+
lines.append(
|
|
483
|
+
f"{i2} if (typeof _kw[_k] === 'object' && _kw[_k] !== null && typeof _v === 'object' && _v !== null) {{"
|
|
484
|
+
)
|
|
485
|
+
lines.append(f"{i2} _kw[_k] = {{..._kw[_k], ..._v}};")
|
|
486
|
+
lines.append(f"{i2} }} else {{")
|
|
487
|
+
lines.append(f"{i2} _kw[_k] = _v;")
|
|
488
|
+
lines.append(f"{i2} }}")
|
|
489
|
+
lines.append(f"{i2}}}")
|
|
490
|
+
lines.append(
|
|
491
|
+
f"{i2}const _resp = await client({url_expr},"
|
|
492
|
+
f" {{ method: {spec.method!r}, ..._kw }});"
|
|
493
|
+
)
|
|
464
494
|
lines.append(
|
|
465
495
|
f"{i2}if (!_resp.ok) throw new Error(`HTTP ${{_resp.status}}`);"
|
|
466
496
|
)
|
|
@@ -469,23 +499,30 @@ def emit_method_fetch(
|
|
|
469
499
|
else:
|
|
470
500
|
lines.extend(_response_lines("await _resp.text()"))
|
|
471
501
|
else:
|
|
472
|
-
|
|
473
|
-
f"{i3}method: {spec.method!r},",
|
|
474
|
-
f"{i3}url: {render_value(spec.url)},",
|
|
475
|
-
]
|
|
502
|
+
url_expr = render_value(spec.url)
|
|
476
503
|
if params_expr:
|
|
477
|
-
|
|
504
|
+
kw_parts.append(f"params: {params_expr}")
|
|
478
505
|
if headers_expr:
|
|
479
|
-
|
|
506
|
+
kw_parts.append(f"headers: {headers_expr}")
|
|
480
507
|
if spec.cookies:
|
|
481
|
-
|
|
482
|
-
f"{i3}// cookies: {render_obj(spec.cookies)},",
|
|
483
|
-
)
|
|
508
|
+
kw_parts.append(f"// cookies: {render_obj(spec.cookies)},")
|
|
484
509
|
if body_expr:
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
lines.
|
|
488
|
-
lines.append(f"{i2}
|
|
510
|
+
kw_parts.append(f"data: {body_expr}")
|
|
511
|
+
kw_obj = "{" + ", ".join(kw_parts) + "}" if kw_parts else "{}"
|
|
512
|
+
lines.append(f"{i2}const _kw = {kw_obj};")
|
|
513
|
+
lines.append(f"{i2}for (const [_k, _v] of Object.entries(opts)) {{")
|
|
514
|
+
lines.append(
|
|
515
|
+
f"{i2} if (typeof _kw[_k] === 'object' && _kw[_k] !== null && typeof _v === 'object' && _v !== null) {{"
|
|
516
|
+
)
|
|
517
|
+
lines.append(f"{i2} _kw[_k] = {{..._kw[_k], ..._v}};")
|
|
518
|
+
lines.append(f"{i2} }} else {{")
|
|
519
|
+
lines.append(f"{i2} _kw[_k] = _v;")
|
|
520
|
+
lines.append(f"{i2} }}")
|
|
521
|
+
lines.append(f"{i2}}}")
|
|
522
|
+
lines.append(
|
|
523
|
+
f"{i2}const _resp = await client.request({{"
|
|
524
|
+
f" method: {spec.method!r}, url: {url_expr}, ..._kw }});"
|
|
525
|
+
)
|
|
489
526
|
lines.extend(_response_lines("_resp.data"))
|
|
490
527
|
|
|
491
528
|
lines.append(f"{i1}}}")
|
|
@@ -296,32 +296,44 @@ def placeholder_args(http: RequestHttp) -> str:
|
|
|
296
296
|
# ===========================================================================
|
|
297
297
|
|
|
298
298
|
|
|
299
|
-
def
|
|
300
|
-
spec: RequestHttp, i2: str, i3: str
|
|
299
|
+
def _build_kw_dict(
|
|
300
|
+
spec: RequestHttp, i2: str, i3: str
|
|
301
301
|
) -> tuple[list[str], list[str]]:
|
|
302
|
-
"""Build (pre_lines,
|
|
302
|
+
"""Build (pre_lines, kw_assign_lines) for ``_kw`` dict construction.
|
|
303
303
|
|
|
304
|
-
|
|
305
|
-
|
|
304
|
+
Produces ``_kw["headers"] = {...}`` style assignments so caller kwargs
|
|
305
|
+
can be shallow-merged into the same dict before passing ``**_kw`` to
|
|
306
|
+
``client.request()`` / ``ssc_rest_call()``.
|
|
307
|
+
|
|
308
|
+
pre_lines: builder helper code (complex dicts needing intermediate vars).
|
|
309
|
+
kw_lines: ``_kw["key"] = value`` assignment lines (at i2 indent).
|
|
306
310
|
"""
|
|
307
311
|
pre_lines: list[str] = []
|
|
308
|
-
|
|
309
|
-
if include_method_url:
|
|
310
|
-
kwargs_lines.append(f"{i3}{spec.method!r},")
|
|
311
|
-
kwargs_lines.append(f"{i3}{render_value(spec.url)},")
|
|
312
|
+
kw_lines: list[str] = []
|
|
312
313
|
for attr, varname in _DICT_KWARGS:
|
|
313
314
|
d = getattr(spec, attr)
|
|
314
315
|
if not d:
|
|
315
316
|
continue
|
|
316
317
|
if dict_needs_builder(d):
|
|
317
318
|
pre_lines.extend(emit_dict_builder(varname, d, i2))
|
|
318
|
-
|
|
319
|
+
kw_lines.append(f'{i2}_kw["{attr}"] = {varname}')
|
|
319
320
|
else:
|
|
320
|
-
|
|
321
|
+
kw_lines.append(f'{i2}_kw["{attr}"] = {render_dict(d)}')
|
|
321
322
|
body_result = render_body(spec)
|
|
322
323
|
if body_result:
|
|
323
|
-
|
|
324
|
-
return pre_lines,
|
|
324
|
+
kw_lines.append(f'{i2}_kw["{body_result[0]}"] = {body_result[1]}')
|
|
325
|
+
return pre_lines, kw_lines
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _merge_loop_lines(i2: str) -> list[str]:
|
|
329
|
+
"""Shallow-merge user kwargs into _kw (dict keys merged key-by-key)."""
|
|
330
|
+
return [
|
|
331
|
+
f"{i2}for _k, _v in kwargs.items():",
|
|
332
|
+
f"{i2} if isinstance(_kw.get(_k), dict) and isinstance(_v, dict):",
|
|
333
|
+
f"{i2} _kw[_k] = {{**_kw[_k], **_v}}",
|
|
334
|
+
f"{i2} else:",
|
|
335
|
+
f"{i2} _kw[_k] = _v",
|
|
336
|
+
]
|
|
325
337
|
|
|
326
338
|
|
|
327
339
|
# ===========================================================================
|
|
@@ -343,9 +355,22 @@ def emit_method_fetch(
|
|
|
343
355
|
i2 = i1 + ctx.indent_char
|
|
344
356
|
i3 = i2 + ctx.indent_char
|
|
345
357
|
|
|
346
|
-
pre_lines,
|
|
347
|
-
|
|
348
|
-
|
|
358
|
+
pre_lines, kw_lines = _build_kw_dict(spec, i2, i3)
|
|
359
|
+
|
|
360
|
+
# kwargs_lines for fetch_body_lines: method, url, **_kw
|
|
361
|
+
fetch_kwargs = [
|
|
362
|
+
f"{i3}{spec.method!r},",
|
|
363
|
+
f"{i3}{render_value(spec.url)},",
|
|
364
|
+
f"{i3}**_kw,",
|
|
365
|
+
]
|
|
366
|
+
|
|
367
|
+
def _kw_setup() -> list[str]:
|
|
368
|
+
"""Lines to build _kw dict + merge user kwargs before the request."""
|
|
369
|
+
setup: list[str] = [f"{i2}_kw: Dict[str, Any] = {{}}"]
|
|
370
|
+
setup.extend(pre_lines)
|
|
371
|
+
setup.extend(kw_lines)
|
|
372
|
+
setup.extend(_merge_loop_lines(i2))
|
|
373
|
+
return setup
|
|
349
374
|
|
|
350
375
|
lines: list[str] = []
|
|
351
376
|
|
|
@@ -353,14 +378,14 @@ def emit_method_fetch(
|
|
|
353
378
|
if http.supports_sync_fetch:
|
|
354
379
|
lines.append(f"{i1}@classmethod")
|
|
355
380
|
lines.append(
|
|
356
|
-
f'{i1}def fetch{suffix}(cls, client: {http.sync_client_type}{ph_params}) -> "{struct_name}":'
|
|
381
|
+
f'{i1}def fetch{suffix}(cls, client: {http.sync_client_type}{ph_params}, **kwargs: Any) -> "{struct_name}":'
|
|
357
382
|
)
|
|
358
|
-
lines.extend(
|
|
383
|
+
lines.extend(_kw_setup())
|
|
359
384
|
lines.extend(
|
|
360
385
|
http.fetch_body_lines(
|
|
361
386
|
is_async=False,
|
|
362
387
|
request_call=f"{i2}_resp = client.request(",
|
|
363
|
-
kwargs_lines=
|
|
388
|
+
kwargs_lines=fetch_kwargs,
|
|
364
389
|
response_path=node.response_path,
|
|
365
390
|
response_join=node.response_join,
|
|
366
391
|
i2=i2,
|
|
@@ -372,24 +397,27 @@ def emit_method_fetch(
|
|
|
372
397
|
# --- async_fetch ------------------------------------------------------
|
|
373
398
|
lines.append(f"{i1}@classmethod")
|
|
374
399
|
lines.append(
|
|
375
|
-
f'{i1}async def async_fetch{suffix}(cls, client: {http.async_client_type}{ph_params}) -> "{struct_name}":'
|
|
400
|
+
f'{i1}async def async_fetch{suffix}(cls, client: {http.async_client_type}{ph_params}, **kwargs: Any) -> "{struct_name}":'
|
|
376
401
|
)
|
|
377
402
|
if http.async_fetch_delegates_to_sync:
|
|
378
403
|
# requests: no native async — run the sync fetch in a worker thread
|
|
379
404
|
# via asyncio.to_thread (non-blocking, yields control to the loop).
|
|
380
|
-
|
|
405
|
+
if ph_kwargs:
|
|
406
|
+
to_thread_args = f"client, {ph_kwargs}, **kwargs"
|
|
407
|
+
else:
|
|
408
|
+
to_thread_args = "client, **kwargs"
|
|
381
409
|
lines.append(f"{i2}import asyncio")
|
|
382
410
|
lines.append(
|
|
383
411
|
f"{i2}return await asyncio.to_thread("
|
|
384
412
|
f"cls.fetch{suffix}, {to_thread_args})"
|
|
385
413
|
)
|
|
386
414
|
else:
|
|
387
|
-
lines.extend(
|
|
415
|
+
lines.extend(_kw_setup())
|
|
388
416
|
lines.extend(
|
|
389
417
|
http.fetch_body_lines(
|
|
390
418
|
is_async=True,
|
|
391
419
|
request_call=f"{i2}_resp = await client.request(",
|
|
392
|
-
kwargs_lines=
|
|
420
|
+
kwargs_lines=fetch_kwargs,
|
|
393
421
|
response_path=node.response_path,
|
|
394
422
|
response_join=node.response_join,
|
|
395
423
|
i2=i2,
|
|
@@ -416,9 +444,7 @@ def emit_method_rest(
|
|
|
416
444
|
|
|
417
445
|
doc_line = f'{i2}"""{node.doc}"""' if node.doc else None
|
|
418
446
|
|
|
419
|
-
pre_lines,
|
|
420
|
-
spec, i2, i3, include_method_url=False
|
|
421
|
-
)
|
|
447
|
+
pre_lines, kw_lines = _build_kw_dict(spec, i2, i3)
|
|
422
448
|
|
|
423
449
|
value_kwarg: list[str] = []
|
|
424
450
|
if node.response_path:
|
|
@@ -431,36 +457,31 @@ def emit_method_rest(
|
|
|
431
457
|
body: list[str] = []
|
|
432
458
|
if doc_line:
|
|
433
459
|
body.append(doc_line)
|
|
460
|
+
body.append(f"{i2}_kw: Dict[str, Any] = {{}}")
|
|
434
461
|
body.extend(pre_lines)
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
# heterogeneous matchers list will produce at runtime). The
|
|
438
|
-
# parser-declared Result alias narrows to the precise union
|
|
439
|
-
# (Err400 | UnknownErr | TransportErr | ...). cast() documents
|
|
440
|
-
# this intent at the call site without suppressing mypy via
|
|
441
|
-
# ``# type: ignore``; the wrapping method's return type is the
|
|
442
|
-
# stable monad consumers see.
|
|
462
|
+
body.extend(kw_lines)
|
|
463
|
+
body.extend(_merge_loop_lines(i2))
|
|
443
464
|
body.append(f"{i2}return cast({ret_type}, {await_kw}{fn_name}(")
|
|
444
465
|
body.append(
|
|
445
466
|
f"{i3}client, {matchers_var}, {spec.method!r},"
|
|
446
467
|
f" {render_value(spec.url)},"
|
|
447
468
|
)
|
|
448
469
|
body.extend(value_kwarg)
|
|
449
|
-
body.
|
|
470
|
+
body.append(f"{i3}**_kw,")
|
|
450
471
|
body.append(f"{i2}))")
|
|
451
472
|
return body
|
|
452
473
|
|
|
453
474
|
lines: list[str] = []
|
|
454
475
|
lines.append(f"{i1}@classmethod")
|
|
455
476
|
lines.append(
|
|
456
|
-
f"{i1}def {method_name}(cls, client: {http.sync_client_type}{ph_params}) -> {ret_type}:"
|
|
477
|
+
f"{i1}def {method_name}(cls, client: {http.sync_client_type}{ph_params}, **kwargs: Any) -> {ret_type}:"
|
|
457
478
|
)
|
|
458
479
|
lines.extend(_body("ssc_rest_call", ""))
|
|
459
480
|
lines.append("")
|
|
460
481
|
|
|
461
482
|
lines.append(f"{i1}@classmethod")
|
|
462
483
|
lines.append(
|
|
463
|
-
f"{i1}async def async_{method_name}(cls, client: {http.async_client_type}{ph_params}) -> {ret_type}:"
|
|
484
|
+
f"{i1}async def async_{method_name}(cls, client: {http.async_client_type}{ph_params}, **kwargs: Any) -> {ret_type}:"
|
|
464
485
|
)
|
|
465
486
|
lines.extend(_body("ssc_rest_call_async", "await "))
|
|
466
487
|
return lines
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ssc_codegen-0.34.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/http_libs/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|