@voxgig/create-sdkgen 0.20.1 → 0.20.3
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/README.md +26 -5
- package/package.json +2 -1
- package/project/standard/.github/workflows/ci.yml +13 -7
- package/project/standard/.sdk/src/Top.ts +8 -0
- package/project/standard/.sdk/test/struct/nullsem.aon +172 -0
- package/project/standard/.sdk/test/struct/test.aon +1 -0
- package/project/standard/.sdk/test/test.json +350 -1
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@ Ruby, Lua, plus a CLI and MCP server).
|
|
|
6
6
|
|
|
7
7
|
## Quickstart
|
|
8
8
|
|
|
9
|
+
From a spec to a tested SDK, in four steps:
|
|
10
|
+
|
|
9
11
|
```sh
|
|
10
12
|
# 1. Scaffold a project from your OpenAPI 3 spec
|
|
11
13
|
create-sdkgen my-api -d ./openapi.yaml -o ./my-api-sdk
|
|
@@ -32,20 +34,39 @@ generated output and is overwritten on each regenerate.
|
|
|
32
34
|
| --- | --- |
|
|
33
35
|
| `<name>` | SDK name (kebab-case), the package base name |
|
|
34
36
|
| `-d, --def <spec>` | OpenAPI 3 spec file (`.yaml`/`.json`) |
|
|
35
|
-
| `-o, --folder <dir>` | output directory |
|
|
37
|
+
| `-o, --folder <dir>` | output directory (default `<name>-sdk`) |
|
|
36
38
|
| `-t, --target <langs>` | targets to add during scaffold (e.g. `ts,py,go`) |
|
|
37
39
|
| `-f, --feature <feats>` | features to add (e.g. `test`) |
|
|
38
40
|
| `--no-install` | skip `npm install` |
|
|
39
41
|
| `-h`, `-v` | help, version |
|
|
40
42
|
|
|
41
|
-
##
|
|
43
|
+
## After the scaffold
|
|
44
|
+
|
|
45
|
+
The loop from here is:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
edit .sdk/model/entity/*.aontu → (cd .sdk && npm run generate) → re-run the target tests
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Commit before regenerating, since generation overwrites the target
|
|
52
|
+
directories. Every generated target carries a `readme_examples` test that
|
|
53
|
+
extracts each code block from that language's `README.md` and `REFERENCE.md`,
|
|
54
|
+
compiles it, and runs the runnable ones in offline test mode, so a documented
|
|
55
|
+
example that does not work fails that target's build. When the tests are
|
|
56
|
+
green, publish each language package the way its ecosystem expects (npm, PyPI,
|
|
57
|
+
Packagist, RubyGems, LuaRocks, or a Go module tag).
|
|
42
58
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
generated, the doc-example test guarantee, and the real-world shape gotchas.
|
|
59
|
+
The step-by-step tutorial, the model reference, and the generator's CLI flags
|
|
60
|
+
are in the [sdkgen documentation](https://github.com/voxgig/sdkgen/tree/main/docs).
|
|
46
61
|
|
|
47
62
|
## The toolchain
|
|
48
63
|
|
|
49
64
|
- **create-sdkgen** (this package) — scaffolds the project.
|
|
50
65
|
- **[@voxgig/apidef](https://github.com/voxgig/apidef)** — parses your OpenAPI spec into the model.
|
|
51
66
|
- **[@voxgig/sdkgen](https://github.com/voxgig/sdkgen)** — generates the SDKs from the model.
|
|
67
|
+
|
|
68
|
+
## Contributing
|
|
69
|
+
|
|
70
|
+
How to validate a change, and why a pull request from a fork gets no CI, are
|
|
71
|
+
in [`CONTRIBUTING.md`](./CONTRIBUTING.md). The documentation follows
|
|
72
|
+
[the style guide](./STYLE-GUIDE.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voxgig/create-sdkgen",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.3",
|
|
4
4
|
"main": "dist/create-sdkgen.js",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"types": "dist/create-sdkgen.d.ts",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"test-some": "node --enable-source-maps --test-name-pattern=\"$npm_config_pattern\" --test dist-test/**/*.test.js",
|
|
27
27
|
"watch": "tsc --build src test -w",
|
|
28
28
|
"build": "tsc --build src test",
|
|
29
|
+
"scan-prose": "python3 tools/check_prose.py",
|
|
29
30
|
"test-model": "voxgig-model project/.sdk/test/test.aon",
|
|
30
31
|
"test-model-watch": "voxgig-model -w project/.sdk/test/test.aon",
|
|
31
32
|
"clean": "rm -rf dist dist-test node_modules yarn.lock package-lock.json",
|
|
@@ -84,7 +84,7 @@ jobs:
|
|
|
84
84
|
- if: hashFiles('go-mcp/go.mod') != ''
|
|
85
85
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7
|
|
86
86
|
with:
|
|
87
|
-
go-version: '1.
|
|
87
|
+
go-version: '1.25'
|
|
88
88
|
- if: hashFiles('go-mcp/go.mod') != ''
|
|
89
89
|
run: |
|
|
90
90
|
cd go-mcp
|
|
@@ -306,17 +306,20 @@ jobs:
|
|
|
306
306
|
continue-on-error: true
|
|
307
307
|
steps:
|
|
308
308
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
309
|
-
# 0.
|
|
310
|
-
#
|
|
311
|
-
#
|
|
312
|
-
#
|
|
309
|
+
# 0.16, matching the generated build.zig.zon's enum-literal `.name` +
|
|
310
|
+
# `.fingerprint` form and the rest of the voxgig toolchain: struct,
|
|
311
|
+
# omni and sekreto all pin 0.16 too. This pin and Package_zig.ts move
|
|
312
|
+
# TOGETHER — the zon form 0.16 requires is exactly what 0.13 cannot
|
|
313
|
+
# parse, so a split leaves the generated SDK unbuildable on one side
|
|
314
|
+
# or the other. It was 0.13 until the target was ported, which is
|
|
315
|
+
# what let omni's zig port be vendored at all.
|
|
313
316
|
# NODE24 EXCEPTION: setup-zig has no node24 release — v1 and v2 are both
|
|
314
317
|
# node20 — so it stays on v1 and will emit a deprecation warning.
|
|
315
318
|
# Revisit when upstream ships one.
|
|
316
319
|
- if: hashFiles('zig/build.zig') != ''
|
|
317
320
|
uses: mlugg/setup-zig@53fc45b17fe98b52f92ee5ea08ff48a85a3e7eb7 # v1
|
|
318
321
|
with:
|
|
319
|
-
version: '0.
|
|
322
|
+
version: '0.16.0'
|
|
320
323
|
- if: hashFiles('zig/build.zig') != ''
|
|
321
324
|
run: make -C zig test
|
|
322
325
|
|
|
@@ -369,7 +372,10 @@ jobs:
|
|
|
369
372
|
with:
|
|
370
373
|
ocaml-compiler: '5.2'
|
|
371
374
|
- if: hashFiles('ocaml/Makefile') != ''
|
|
372
|
-
|
|
375
|
+
# setup-ocaml installs the compiler into an opam switch; without
|
|
376
|
+
# `opam exec` the switch is not on PATH and make dies with
|
|
377
|
+
# `ocamlc: No such file or directory` (exit 127).
|
|
378
|
+
run: opam exec -- make -C ocaml test
|
|
373
379
|
|
|
374
380
|
haskell:
|
|
375
381
|
runs-on: ubuntu-latest
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import {
|
|
4
4
|
cmp,
|
|
5
5
|
Deploy,
|
|
6
|
+
PublishWorkflow,
|
|
6
7
|
ReadmeTop,
|
|
7
8
|
AgentGuideTop,
|
|
8
9
|
License,
|
|
@@ -30,6 +31,13 @@ const Top = cmp(function Top(props: any) {
|
|
|
30
31
|
// credentials injected by the aql key vault) plus an all-targets
|
|
31
32
|
// `make deploy-dry` rehearsal.
|
|
32
33
|
Deploy({})
|
|
34
|
+
|
|
35
|
+
// Publishing an npm target from CI with no token: a dispatch workflow per
|
|
36
|
+
// npm target using GitHub OIDC trusted publishing, and the one-time
|
|
37
|
+
// set-up a maintainer must do, written to `.sdk/PUBLISHING.md` — beside
|
|
38
|
+
// the generator rather than into the target's own docs, which describe
|
|
39
|
+
// the SDK to the people who install it.
|
|
40
|
+
PublishWorkflow({})
|
|
33
41
|
})
|
|
34
42
|
|
|
35
43
|
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
|
|
2
|
+
# STORED-NULL SEMANTICS.
|
|
3
|
+
#
|
|
4
|
+
# One question, asked of every reader: when a key is PRESENT and holds a JSON
|
|
5
|
+
# null, is that "no value" (the same as an absent key) or is it a value?
|
|
6
|
+
#
|
|
7
|
+
# Nothing in the corpus asked it before. `minor.getprop` and `minor.haskey`
|
|
8
|
+
# have ~50 cases each and not one stores a null: every entry is an absent key
|
|
9
|
+
# or a non-null value. So the ports diverged silently, and they HAVE:
|
|
10
|
+
#
|
|
11
|
+
# port getprop({x:null},'x','ALT') haskey({x:null},'x')
|
|
12
|
+
# ──── ─────────────────────────── ────────────────────
|
|
13
|
+
# go 'ALT' false
|
|
14
|
+
# py 'ALT' false
|
|
15
|
+
# perl 'ALT' false
|
|
16
|
+
# rb null true
|
|
17
|
+
# php null true
|
|
18
|
+
# js null true
|
|
19
|
+
#
|
|
20
|
+
# That is not academic. It is the direct cause of the `auth: null` bug family:
|
|
21
|
+
# `auth: null` is the documented way to suppress auth outright, and where a
|
|
22
|
+
# stored null reads as "no value" the optspec `auth` default fires, the
|
|
23
|
+
# suppression becomes "use the default auth", and the credential the caller
|
|
24
|
+
# withheld goes out on the wire.
|
|
25
|
+
#
|
|
26
|
+
# 0.3.2 answers "no value" — the top three rows. This section pins that.
|
|
27
|
+
#
|
|
28
|
+
#
|
|
29
|
+
# THIS SECTION IS OPT-IN, AND DELIBERATELY SO.
|
|
30
|
+
#
|
|
31
|
+
# Half the tree still vendors a struct that answers the other way. Putting
|
|
32
|
+
# these cases in `minor` would red those targets today and gate the whole
|
|
33
|
+
# corpus on finishing the struct migration everywhere first. Instead a target
|
|
34
|
+
# wires this section up as it migrates:
|
|
35
|
+
#
|
|
36
|
+
# runsetflags(nullsemSpec["getprop"], {"null": False}, getprop_wrapper)
|
|
37
|
+
#
|
|
38
|
+
# so the section becomes that target's null-semantics gate, and a target that
|
|
39
|
+
# has not migrated simply does not reference it yet.
|
|
40
|
+
#
|
|
41
|
+
#
|
|
42
|
+
# `null: false` IS NOT OPTIONAL HERE.
|
|
43
|
+
#
|
|
44
|
+
# The runner's default fixJSON rewrites every JSON null - on BOTH the `in` and
|
|
45
|
+
# `out` sides - to the string '__NULL__' before the subject ever sees it. Run
|
|
46
|
+
# without the flag, every case below would pass the STRING '__NULL__' as the
|
|
47
|
+
# stored value, which is not a null and is not the question. The section would
|
|
48
|
+
# then pass on every port while asserting nothing about null at all - the
|
|
49
|
+
# exact "green while checking nothing" failure the corpus guards exist to
|
|
50
|
+
# prevent. `minor.getelem` and `minor.clone` already run with the flag for the
|
|
51
|
+
# same reason.
|
|
52
|
+
#
|
|
53
|
+
# With the flag, an entry with NO `out` expects a null result, and `out:` with
|
|
54
|
+
# a value expects that value.
|
|
55
|
+
#
|
|
56
|
+
#
|
|
57
|
+
# VERIFIED AGAINST THE REFERENCE, NOT GUESSED.
|
|
58
|
+
#
|
|
59
|
+
# All 33 cases below were run against upstream @voxgig/struct 0.3.2
|
|
60
|
+
# (typescript/src/StructUtility.ts, the canonical port) and all 33 pass. They
|
|
61
|
+
# are what the reference DOES, not what it was assumed to do.
|
|
62
|
+
#
|
|
63
|
+
# That mattered on the first run: `getprop([null], 0, 'ALT')` was assumed to
|
|
64
|
+
# be a formality and turned out to be a live defect in the py port's vendored
|
|
65
|
+
# copy. Canonical getprop tests `isnode(val)` - map AND list - and then
|
|
66
|
+
# applies the null rule once to whatever it read. The py copy branches on
|
|
67
|
+
# ismap/islist and its list branch does `return val[key]`, an early return
|
|
68
|
+
# that skips the null check entirely, so it hands back the stored null where
|
|
69
|
+
# every other reader would substitute the alt. Its map path is correct, which
|
|
70
|
+
# is why nothing noticed.
|
|
71
|
+
#
|
|
72
|
+
# So py cannot opt in to this section until its vendored struct is resynced.
|
|
73
|
+
# That is the section working as intended: it says "not yet" in a test result
|
|
74
|
+
# instead of in a comment.
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# Does the ALT fire for a stored null, as it does for an absent key?
|
|
78
|
+
getprop: {
|
|
79
|
+
set: [
|
|
80
|
+
# THE CASE. Absent and stored-null must answer alike.
|
|
81
|
+
{ in: { val: {x:null}, key: x, alt: 'ALT' }, out: 'ALT' }
|
|
82
|
+
{ in: { val: {}, key: x, alt: 'ALT' }, out: 'ALT' }
|
|
83
|
+
|
|
84
|
+
# No alt: a stored null reads back as null either way, so this pins that
|
|
85
|
+
# the rule does not turn a null into something else.
|
|
86
|
+
{ in: { val: {x:null}, key: x } }
|
|
87
|
+
|
|
88
|
+
# A stored null must not leak past its own key.
|
|
89
|
+
{ in: { val: {x:null, y:1}, key: y, alt: 'ALT' }, out: 1 }
|
|
90
|
+
{ in: { val: {x:1, y:null}, key: x, alt: 'ALT' }, out: 1 }
|
|
91
|
+
|
|
92
|
+
# false, 0 and '' are VALUES, not absence. A port that collapses "nullish"
|
|
93
|
+
# to "falsy" passes every case above and fails these.
|
|
94
|
+
{ in: { val: {x:false}, key: x, alt: 'ALT' }, out: false }
|
|
95
|
+
{ in: { val: {x:0}, key: x, alt: 'ALT' }, out: 0 }
|
|
96
|
+
{ in: { val: {x:''}, key: x, alt: 'ALT' }, out: '' }
|
|
97
|
+
|
|
98
|
+
# Lists too: index 0 holding a null is the list-shaped form of the same
|
|
99
|
+
# question, and a port can easily fix one and not the other.
|
|
100
|
+
{ in: { val: [null], key: 0, alt: 'ALT' }, out: 'ALT' }
|
|
101
|
+
{ in: { val: [null, 1], key: 1, alt: 'ALT' }, out: 1 }
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# getelem is the list-index reader. Same rule, different entry point - and it
|
|
107
|
+
# is a separate function in every port, so it needs its own cases.
|
|
108
|
+
getelem: {
|
|
109
|
+
set: [
|
|
110
|
+
{ in: { val: [null], key: 0, alt: 'ALT' }, out: 'ALT' }
|
|
111
|
+
{ in: { val: [10, null, 30], key: 1, alt: 'ALT' }, out: 'ALT' }
|
|
112
|
+
{ in: { val: [10, null, 30], key: 2, alt: 'ALT' }, out: 30 }
|
|
113
|
+
|
|
114
|
+
# Negative indices are getelem's whole reason for existing; a stored null
|
|
115
|
+
# at a negative index is the case a port is most likely to miss.
|
|
116
|
+
{ in: { val: [10, null], key: -1, alt: 'ALT' }, out: 'ALT' }
|
|
117
|
+
{ in: { val: [null, 20], key: -1, alt: 'ALT' }, out: 20 }
|
|
118
|
+
|
|
119
|
+
{ in: { val: [false], key: 0, alt: 'ALT' }, out: false }
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# A path that lands on a stored null, and - the case that actually bites - a
|
|
125
|
+
# path that must TRAVERSE one. Traversal through a null is not the same
|
|
126
|
+
# question as reading one, and a port can get the leaf right and still walk
|
|
127
|
+
# into a null parent.
|
|
128
|
+
getpath: {
|
|
129
|
+
set: [
|
|
130
|
+
{ in: { path: 'a', store: {a:null} } }
|
|
131
|
+
{ in: { path: 'a.b', store: {a:null} } }
|
|
132
|
+
{ in: { path: 'a.b.c', store: {a:{b:null}} } }
|
|
133
|
+
{ in: { path: 'a.b', store: {a:{b:null}} } }
|
|
134
|
+
{ in: { path: 'a.b', store: {a:{b:1}} }, out: 1 }
|
|
135
|
+
{ in: { path: 'a.b', store: {a:{b:false}} }, out: false }
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# Presence, asked directly. This is the reader the auth-null fix needs in
|
|
141
|
+
# every port, and the one whose answer splits the tree.
|
|
142
|
+
haskey: {
|
|
143
|
+
set: [
|
|
144
|
+
{ in: { src: {x:null}, key: x }, out: false }
|
|
145
|
+
{ in: { src: {}, key: x }, out: false }
|
|
146
|
+
{ in: { src: {x:1}, key: x }, out: true }
|
|
147
|
+
|
|
148
|
+
# Again: falsy is not absent.
|
|
149
|
+
{ in: { src: {x:false}, key: x }, out: true }
|
|
150
|
+
{ in: { src: {x:0}, key: x }, out: true }
|
|
151
|
+
{ in: { src: {x:''}, key: x }, out: true }
|
|
152
|
+
|
|
153
|
+
{ in: { src: [null], key: 0 }, out: false }
|
|
154
|
+
{ in: { src: [1], key: 0 }, out: true }
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# The other direction, and the reason `auth: null` is expressible at all:
|
|
160
|
+
# presence is STRUCTURAL. keysof lists a null-valued key, because the key IS
|
|
161
|
+
# there - it is only the READERS above that treat its value as no value.
|
|
162
|
+
#
|
|
163
|
+
# A port that made haskey false by DELETING the key would pass every case
|
|
164
|
+
# above and fail here, and it would also make the suppression unwritable:
|
|
165
|
+
# there would be nothing left for makeOptions to detect.
|
|
166
|
+
keysof: {
|
|
167
|
+
set: [
|
|
168
|
+
{ in: {a:null}, out: [a] }
|
|
169
|
+
{ in: {a:null, b:1}, out: [a, b] }
|
|
170
|
+
{ in: {a:1, b:null}, out: [a, b] }
|
|
171
|
+
]
|
|
172
|
+
}
|
|
@@ -1543,7 +1543,11 @@
|
|
|
1543
1543
|
"DEF": {
|
|
1544
1544
|
"setup": {
|
|
1545
1545
|
"a": {
|
|
1546
|
-
"apikey": "APIKEY01"
|
|
1546
|
+
"apikey": "APIKEY01",
|
|
1547
|
+
"auth": {
|
|
1548
|
+
"basic": false,
|
|
1549
|
+
"prefix": ""
|
|
1550
|
+
}
|
|
1547
1551
|
}
|
|
1548
1552
|
}
|
|
1549
1553
|
},
|
|
@@ -10276,6 +10280,351 @@
|
|
|
10276
10280
|
]
|
|
10277
10281
|
}
|
|
10278
10282
|
},
|
|
10283
|
+
"nullsem": {
|
|
10284
|
+
"getelem": {
|
|
10285
|
+
"set": [
|
|
10286
|
+
{
|
|
10287
|
+
"in": {
|
|
10288
|
+
"alt": "ALT",
|
|
10289
|
+
"key": 0,
|
|
10290
|
+
"val": [
|
|
10291
|
+
null
|
|
10292
|
+
]
|
|
10293
|
+
},
|
|
10294
|
+
"out": "ALT"
|
|
10295
|
+
},
|
|
10296
|
+
{
|
|
10297
|
+
"in": {
|
|
10298
|
+
"alt": "ALT",
|
|
10299
|
+
"key": 1,
|
|
10300
|
+
"val": [
|
|
10301
|
+
10,
|
|
10302
|
+
null,
|
|
10303
|
+
30
|
|
10304
|
+
]
|
|
10305
|
+
},
|
|
10306
|
+
"out": "ALT"
|
|
10307
|
+
},
|
|
10308
|
+
{
|
|
10309
|
+
"in": {
|
|
10310
|
+
"alt": "ALT",
|
|
10311
|
+
"key": 2,
|
|
10312
|
+
"val": [
|
|
10313
|
+
10,
|
|
10314
|
+
null,
|
|
10315
|
+
30
|
|
10316
|
+
]
|
|
10317
|
+
},
|
|
10318
|
+
"out": 30
|
|
10319
|
+
},
|
|
10320
|
+
{
|
|
10321
|
+
"in": {
|
|
10322
|
+
"alt": "ALT",
|
|
10323
|
+
"key": -1,
|
|
10324
|
+
"val": [
|
|
10325
|
+
10,
|
|
10326
|
+
null
|
|
10327
|
+
]
|
|
10328
|
+
},
|
|
10329
|
+
"out": "ALT"
|
|
10330
|
+
},
|
|
10331
|
+
{
|
|
10332
|
+
"in": {
|
|
10333
|
+
"alt": "ALT",
|
|
10334
|
+
"key": -1,
|
|
10335
|
+
"val": [
|
|
10336
|
+
null,
|
|
10337
|
+
20
|
|
10338
|
+
]
|
|
10339
|
+
},
|
|
10340
|
+
"out": 20
|
|
10341
|
+
},
|
|
10342
|
+
{
|
|
10343
|
+
"in": {
|
|
10344
|
+
"alt": "ALT",
|
|
10345
|
+
"key": 0,
|
|
10346
|
+
"val": [
|
|
10347
|
+
false
|
|
10348
|
+
]
|
|
10349
|
+
},
|
|
10350
|
+
"out": false
|
|
10351
|
+
}
|
|
10352
|
+
]
|
|
10353
|
+
},
|
|
10354
|
+
"getpath": {
|
|
10355
|
+
"set": [
|
|
10356
|
+
{
|
|
10357
|
+
"in": {
|
|
10358
|
+
"path": "a",
|
|
10359
|
+
"store": {
|
|
10360
|
+
"a": null
|
|
10361
|
+
}
|
|
10362
|
+
}
|
|
10363
|
+
},
|
|
10364
|
+
{
|
|
10365
|
+
"in": {
|
|
10366
|
+
"path": "a.b",
|
|
10367
|
+
"store": {
|
|
10368
|
+
"a": null
|
|
10369
|
+
}
|
|
10370
|
+
}
|
|
10371
|
+
},
|
|
10372
|
+
{
|
|
10373
|
+
"in": {
|
|
10374
|
+
"path": "a.b.c",
|
|
10375
|
+
"store": {
|
|
10376
|
+
"a": {
|
|
10377
|
+
"b": null
|
|
10378
|
+
}
|
|
10379
|
+
}
|
|
10380
|
+
}
|
|
10381
|
+
},
|
|
10382
|
+
{
|
|
10383
|
+
"in": {
|
|
10384
|
+
"path": "a.b",
|
|
10385
|
+
"store": {
|
|
10386
|
+
"a": {
|
|
10387
|
+
"b": null
|
|
10388
|
+
}
|
|
10389
|
+
}
|
|
10390
|
+
}
|
|
10391
|
+
},
|
|
10392
|
+
{
|
|
10393
|
+
"in": {
|
|
10394
|
+
"path": "a.b",
|
|
10395
|
+
"store": {
|
|
10396
|
+
"a": {
|
|
10397
|
+
"b": 1
|
|
10398
|
+
}
|
|
10399
|
+
}
|
|
10400
|
+
},
|
|
10401
|
+
"out": 1
|
|
10402
|
+
},
|
|
10403
|
+
{
|
|
10404
|
+
"in": {
|
|
10405
|
+
"path": "a.b",
|
|
10406
|
+
"store": {
|
|
10407
|
+
"a": {
|
|
10408
|
+
"b": false
|
|
10409
|
+
}
|
|
10410
|
+
}
|
|
10411
|
+
},
|
|
10412
|
+
"out": false
|
|
10413
|
+
}
|
|
10414
|
+
]
|
|
10415
|
+
},
|
|
10416
|
+
"getprop": {
|
|
10417
|
+
"set": [
|
|
10418
|
+
{
|
|
10419
|
+
"in": {
|
|
10420
|
+
"alt": "ALT",
|
|
10421
|
+
"key": "x",
|
|
10422
|
+
"val": {
|
|
10423
|
+
"x": null
|
|
10424
|
+
}
|
|
10425
|
+
},
|
|
10426
|
+
"out": "ALT"
|
|
10427
|
+
},
|
|
10428
|
+
{
|
|
10429
|
+
"in": {
|
|
10430
|
+
"alt": "ALT",
|
|
10431
|
+
"key": "x",
|
|
10432
|
+
"val": {}
|
|
10433
|
+
},
|
|
10434
|
+
"out": "ALT"
|
|
10435
|
+
},
|
|
10436
|
+
{
|
|
10437
|
+
"in": {
|
|
10438
|
+
"key": "x",
|
|
10439
|
+
"val": {
|
|
10440
|
+
"x": null
|
|
10441
|
+
}
|
|
10442
|
+
}
|
|
10443
|
+
},
|
|
10444
|
+
{
|
|
10445
|
+
"in": {
|
|
10446
|
+
"alt": "ALT",
|
|
10447
|
+
"key": "y",
|
|
10448
|
+
"val": {
|
|
10449
|
+
"x": null,
|
|
10450
|
+
"y": 1
|
|
10451
|
+
}
|
|
10452
|
+
},
|
|
10453
|
+
"out": 1
|
|
10454
|
+
},
|
|
10455
|
+
{
|
|
10456
|
+
"in": {
|
|
10457
|
+
"alt": "ALT",
|
|
10458
|
+
"key": "x",
|
|
10459
|
+
"val": {
|
|
10460
|
+
"x": 1,
|
|
10461
|
+
"y": null
|
|
10462
|
+
}
|
|
10463
|
+
},
|
|
10464
|
+
"out": 1
|
|
10465
|
+
},
|
|
10466
|
+
{
|
|
10467
|
+
"in": {
|
|
10468
|
+
"alt": "ALT",
|
|
10469
|
+
"key": "x",
|
|
10470
|
+
"val": {
|
|
10471
|
+
"x": false
|
|
10472
|
+
}
|
|
10473
|
+
},
|
|
10474
|
+
"out": false
|
|
10475
|
+
},
|
|
10476
|
+
{
|
|
10477
|
+
"in": {
|
|
10478
|
+
"alt": "ALT",
|
|
10479
|
+
"key": "x",
|
|
10480
|
+
"val": {
|
|
10481
|
+
"x": 0
|
|
10482
|
+
}
|
|
10483
|
+
},
|
|
10484
|
+
"out": 0
|
|
10485
|
+
},
|
|
10486
|
+
{
|
|
10487
|
+
"in": {
|
|
10488
|
+
"alt": "ALT",
|
|
10489
|
+
"key": "x",
|
|
10490
|
+
"val": {
|
|
10491
|
+
"x": ""
|
|
10492
|
+
}
|
|
10493
|
+
},
|
|
10494
|
+
"out": ""
|
|
10495
|
+
},
|
|
10496
|
+
{
|
|
10497
|
+
"in": {
|
|
10498
|
+
"alt": "ALT",
|
|
10499
|
+
"key": 0,
|
|
10500
|
+
"val": [
|
|
10501
|
+
null
|
|
10502
|
+
]
|
|
10503
|
+
},
|
|
10504
|
+
"out": "ALT"
|
|
10505
|
+
},
|
|
10506
|
+
{
|
|
10507
|
+
"in": {
|
|
10508
|
+
"alt": "ALT",
|
|
10509
|
+
"key": 1,
|
|
10510
|
+
"val": [
|
|
10511
|
+
null,
|
|
10512
|
+
1
|
|
10513
|
+
]
|
|
10514
|
+
},
|
|
10515
|
+
"out": 1
|
|
10516
|
+
}
|
|
10517
|
+
]
|
|
10518
|
+
},
|
|
10519
|
+
"haskey": {
|
|
10520
|
+
"set": [
|
|
10521
|
+
{
|
|
10522
|
+
"in": {
|
|
10523
|
+
"key": "x",
|
|
10524
|
+
"src": {
|
|
10525
|
+
"x": null
|
|
10526
|
+
}
|
|
10527
|
+
},
|
|
10528
|
+
"out": false
|
|
10529
|
+
},
|
|
10530
|
+
{
|
|
10531
|
+
"in": {
|
|
10532
|
+
"key": "x",
|
|
10533
|
+
"src": {}
|
|
10534
|
+
},
|
|
10535
|
+
"out": false
|
|
10536
|
+
},
|
|
10537
|
+
{
|
|
10538
|
+
"in": {
|
|
10539
|
+
"key": "x",
|
|
10540
|
+
"src": {
|
|
10541
|
+
"x": 1
|
|
10542
|
+
}
|
|
10543
|
+
},
|
|
10544
|
+
"out": true
|
|
10545
|
+
},
|
|
10546
|
+
{
|
|
10547
|
+
"in": {
|
|
10548
|
+
"key": "x",
|
|
10549
|
+
"src": {
|
|
10550
|
+
"x": false
|
|
10551
|
+
}
|
|
10552
|
+
},
|
|
10553
|
+
"out": true
|
|
10554
|
+
},
|
|
10555
|
+
{
|
|
10556
|
+
"in": {
|
|
10557
|
+
"key": "x",
|
|
10558
|
+
"src": {
|
|
10559
|
+
"x": 0
|
|
10560
|
+
}
|
|
10561
|
+
},
|
|
10562
|
+
"out": true
|
|
10563
|
+
},
|
|
10564
|
+
{
|
|
10565
|
+
"in": {
|
|
10566
|
+
"key": "x",
|
|
10567
|
+
"src": {
|
|
10568
|
+
"x": ""
|
|
10569
|
+
}
|
|
10570
|
+
},
|
|
10571
|
+
"out": true
|
|
10572
|
+
},
|
|
10573
|
+
{
|
|
10574
|
+
"in": {
|
|
10575
|
+
"key": 0,
|
|
10576
|
+
"src": [
|
|
10577
|
+
null
|
|
10578
|
+
]
|
|
10579
|
+
},
|
|
10580
|
+
"out": false
|
|
10581
|
+
},
|
|
10582
|
+
{
|
|
10583
|
+
"in": {
|
|
10584
|
+
"key": 0,
|
|
10585
|
+
"src": [
|
|
10586
|
+
1
|
|
10587
|
+
]
|
|
10588
|
+
},
|
|
10589
|
+
"out": true
|
|
10590
|
+
}
|
|
10591
|
+
]
|
|
10592
|
+
},
|
|
10593
|
+
"keysof": {
|
|
10594
|
+
"set": [
|
|
10595
|
+
{
|
|
10596
|
+
"in": {
|
|
10597
|
+
"a": null
|
|
10598
|
+
},
|
|
10599
|
+
"out": [
|
|
10600
|
+
"a"
|
|
10601
|
+
]
|
|
10602
|
+
},
|
|
10603
|
+
{
|
|
10604
|
+
"in": {
|
|
10605
|
+
"a": null,
|
|
10606
|
+
"b": 1
|
|
10607
|
+
},
|
|
10608
|
+
"out": [
|
|
10609
|
+
"a",
|
|
10610
|
+
"b"
|
|
10611
|
+
]
|
|
10612
|
+
},
|
|
10613
|
+
{
|
|
10614
|
+
"in": {
|
|
10615
|
+
"a": 1,
|
|
10616
|
+
"b": null
|
|
10617
|
+
},
|
|
10618
|
+
"out": [
|
|
10619
|
+
"a",
|
|
10620
|
+
"b"
|
|
10621
|
+
]
|
|
10622
|
+
}
|
|
10623
|
+
]
|
|
10624
|
+
},
|
|
10625
|
+
"name": "nullsem",
|
|
10626
|
+
"set": []
|
|
10627
|
+
},
|
|
10279
10628
|
"select": {
|
|
10280
10629
|
"alts": {
|
|
10281
10630
|
"data": {
|