@voxgig/sdkgen 3.3.2 → 3.4.2
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/dist/cmp/Readme.js +2 -0
- package/dist/cmp/Readme.js.map +1 -1
- package/dist/cmp/ReadmeUnions.d.ts +3 -0
- package/dist/cmp/ReadmeUnions.js +74 -0
- package/dist/cmp/ReadmeUnions.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/project/.sdk/src/cmp/c/Config_c.ts +1 -1
- package/project/.sdk/src/cmp/c/utility_c.ts +57 -6
- package/project/.sdk/src/cmp/clojure/Config_clojure.ts +1 -1
- package/project/.sdk/src/cmp/clojure/utility_clojure.ts +57 -6
- package/project/.sdk/src/cmp/cpp/Config_cpp.ts +1 -1
- package/project/.sdk/src/cmp/cpp/utility_cpp.ts +57 -6
- package/project/.sdk/src/cmp/csharp/Config_csharp.ts +1 -1
- package/project/.sdk/src/cmp/csharp/utility_csharp.ts +57 -6
- package/project/.sdk/src/cmp/dart/Config_dart.ts +1 -1
- package/project/.sdk/src/cmp/dart/utility_dart.ts +57 -6
- package/project/.sdk/src/cmp/elixir/Config_elixir.ts +1 -1
- package/project/.sdk/src/cmp/elixir/utility_elixir.ts +57 -6
- package/project/.sdk/src/cmp/go/Config_go.ts +27 -2
- package/project/.sdk/src/cmp/go/Main_go.ts +1 -0
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +1 -1
- package/project/.sdk/src/cmp/go/fragment/Main.fragment.go +1 -1
- package/project/.sdk/src/cmp/go/utility_go.ts +57 -6
- package/project/.sdk/src/cmp/haskell/Config_haskell.ts +1 -1
- package/project/.sdk/src/cmp/haskell/utility_haskell.ts +57 -6
- package/project/.sdk/src/cmp/java/Config_java.ts +1 -1
- package/project/.sdk/src/cmp/java/utility_java.ts +57 -6
- package/project/.sdk/src/cmp/js/Config_js.ts +1 -1
- package/project/.sdk/src/cmp/js/utility_js.ts +57 -6
- package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +1 -1
- package/project/.sdk/src/cmp/kotlin/utility_kotlin.ts +57 -6
- package/project/.sdk/src/cmp/lean/Config_lean.ts +1 -1
- package/project/.sdk/src/cmp/lean/utility_lean.ts +57 -6
- package/project/.sdk/src/cmp/lua/Config_lua.ts +30 -1
- package/project/.sdk/src/cmp/lua/Package_lua.ts +1 -0
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +1 -1
- package/project/.sdk/src/cmp/lua/fragment/Main.fragment.lua +1 -1
- package/project/.sdk/src/cmp/lua/utility_lua.ts +57 -6
- package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +1 -1
- package/project/.sdk/src/cmp/ocaml/utility_ocaml.ts +57 -6
- package/project/.sdk/src/cmp/perl/Config_perl.ts +1 -1
- package/project/.sdk/src/cmp/perl/utility_perl.ts +57 -6
- package/project/.sdk/src/cmp/php/Config_php.ts +24 -1
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +1 -1
- package/project/.sdk/src/cmp/php/fragment/Entity.fragment.php +22 -0
- package/project/.sdk/src/cmp/php/fragment/Main.fragment.php +1 -1
- package/project/.sdk/src/cmp/php/utility_php.ts +57 -6
- package/project/.sdk/src/cmp/py/Config_py.ts +24 -1
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +2 -2
- package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +2 -2
- package/project/.sdk/src/cmp/py/utility_py.ts +57 -6
- package/project/.sdk/src/cmp/rb/Config_rb.ts +15 -1
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +1 -1
- package/project/.sdk/src/cmp/rb/fragment/Main.fragment.rb +1 -1
- package/project/.sdk/src/cmp/rb/utility_rb.ts +57 -6
- package/project/.sdk/src/cmp/rust/Config_rust.ts +1 -1
- package/project/.sdk/src/cmp/rust/utility_rust.ts +57 -6
- package/project/.sdk/src/cmp/scala/Config_scala.ts +1 -1
- package/project/.sdk/src/cmp/scala/utility_scala.ts +57 -6
- package/project/.sdk/src/cmp/swift/Config_swift.ts +1 -1
- package/project/.sdk/src/cmp/swift/utility_swift.ts +57 -6
- package/project/.sdk/src/cmp/ts/Config_ts.ts +1 -1
- package/project/.sdk/src/cmp/ts/utility_ts.ts +57 -6
- package/project/.sdk/src/cmp/zig/Config_zig.ts +1 -1
- package/project/.sdk/src/cmp/zig/utility_zig.ts +57 -6
- package/project/.sdk/tm/c/core/point.c +2 -1
- package/project/.sdk/tm/csharp/core/Point.cs +3 -1
- package/project/.sdk/tm/dart/lib/Point.dart +2 -1
- package/project/.sdk/tm/go/test/feature_harness_test.go +1 -1
- package/project/.sdk/tm/go/utility/make_options.go +5 -1
- package/project/.sdk/tm/java/core/Point.java +3 -1
- package/project/.sdk/tm/js/src/Point.js +3 -1
- package/project/.sdk/tm/kotlin/core/Point.kt +3 -1
- package/project/.sdk/tm/lua/utility/make_options.lua +5 -1
- package/project/.sdk/tm/php/test/FeatureTest.php +1 -1
- package/project/.sdk/tm/py/pkg/utility/make_options.py +5 -1
- package/project/.sdk/tm/py/test/feature_harness.py +2 -2
- package/project/.sdk/tm/rb/test/feature_test.rb +1 -1
- package/project/.sdk/tm/rb/utility/make_options.rb +5 -1
- package/project/.sdk/tm/scala/core/Point.scala +2 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/core/Point.swift +3 -1
- package/project/.sdk/tm/ts/src/Point.ts +3 -1
- package/project/.sdk/tm/zig/core/point.zig +2 -1
- package/src/cmp/Readme.ts +2 -0
- package/src/cmp/ReadmeUnions.ts +90 -0
|
@@ -57,13 +57,64 @@ function swiftString(val: string): string {
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
// Strip model-internal keys (ending in `$`) from a cloned value graph.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
// Emission-time normalisation of a model subtree (L0).
|
|
61
|
+
//
|
|
62
|
+
// Always drops jostraca's iteration metadata (`$`-suffixed keys: index$,
|
|
63
|
+
// key$, val$). With `dropDefaults`, also drops keys whose value IS the
|
|
64
|
+
// default the runtime already assumes when the key is absent, which is pure
|
|
65
|
+
// payload — see CONFIG_DEFAULT.
|
|
66
|
+
//
|
|
67
|
+
// Rebuilds the tree rather than mutating during a walk. The previous
|
|
68
|
+
// implementation walked a clone calling `delete p[k]`, but walk() assigns its
|
|
69
|
+
// callback's result back over the child (`setprop(out, ckey, walk(...))`), so
|
|
70
|
+
// the delete was undone on the way out and the helper silently did nothing.
|
|
71
|
+
// Returning `undefined` from the callback does not fix it either: setprop
|
|
72
|
+
// stores undefined rather than removing the key, which then emits as a null.
|
|
73
|
+
//
|
|
74
|
+
// `dropDefaults` is opt-in and must be passed ONLY for the entity subtree.
|
|
75
|
+
// `active` means something different in feature config, where absent reads as
|
|
76
|
+
// INACTIVE (see feature_init) — dropping `active: true` there would silently
|
|
77
|
+
// disable the feature.
|
|
78
|
+
// jostraca's iteration metadata, injected by each()/names() while it walks the
|
|
79
|
+
// model. Listed explicitly rather than matched by trailing-dollar suffix: a
|
|
80
|
+
// trailing dollar is not exclusive to jostraca -- Seneca uses entity$ as real
|
|
81
|
+
// data -- so a blanket suffix match can silently drop a legitimate API field.
|
|
82
|
+
const MODEL_META = ['index$', 'key$', 'val$']
|
|
83
|
+
|
|
84
|
+
// Keys whose value IS the default the runtime already assumes when the key is
|
|
85
|
+
// absent, so emitting them is pure payload.
|
|
86
|
+
const CONFIG_DEFAULT: Record<string, any> = {
|
|
87
|
+
active: true,
|
|
88
|
+
req: false,
|
|
89
|
+
reqd: false,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Subtrees carrying user payload rather than schema. An active:true inside an
|
|
93
|
+
// OpenAPI example is DATA, not a default, so default-pruning stops at these
|
|
94
|
+
// keys and everything below them is passed through untouched.
|
|
95
|
+
const PAYLOAD_KEYS = ['default', 'example', 'examples']
|
|
96
|
+
|
|
97
|
+
function clean(o: any, dropDefaults?: boolean): any {
|
|
98
|
+
const prune = (node: any, defaults: boolean): any => {
|
|
99
|
+
if (Array.isArray(node)) {
|
|
100
|
+
return node.map((n: any) => prune(n, defaults))
|
|
101
|
+
}
|
|
102
|
+
if (null != node && 'object' === typeof node) {
|
|
103
|
+
const out: any = {}
|
|
104
|
+
for (const k of Object.keys(node)) {
|
|
105
|
+
if (MODEL_META.includes(k)) {
|
|
106
|
+
continue
|
|
107
|
+
}
|
|
108
|
+
if (defaults && k in CONFIG_DEFAULT && CONFIG_DEFAULT[k] === node[k]) {
|
|
109
|
+
continue
|
|
110
|
+
}
|
|
111
|
+
out[k] = prune(node[k], defaults && !PAYLOAD_KEYS.includes(k))
|
|
112
|
+
}
|
|
113
|
+
return out
|
|
64
114
|
}
|
|
65
|
-
return
|
|
66
|
-
}
|
|
115
|
+
return node
|
|
116
|
+
}
|
|
117
|
+
return prune(o, true === dropDefaults)
|
|
67
118
|
}
|
|
68
119
|
|
|
69
120
|
|
|
@@ -104,13 +104,64 @@ function formatJson(obj: any, flags?: { line?: boolean, margin?: number }): stri
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
// Emission-time normalisation of a model subtree (L0).
|
|
108
|
+
//
|
|
109
|
+
// Always drops jostraca's iteration metadata (`$`-suffixed keys: index$,
|
|
110
|
+
// key$, val$). With `dropDefaults`, also drops keys whose value IS the
|
|
111
|
+
// default the runtime already assumes when the key is absent, which is pure
|
|
112
|
+
// payload — see CONFIG_DEFAULT.
|
|
113
|
+
//
|
|
114
|
+
// Rebuilds the tree rather than mutating during a walk. The previous
|
|
115
|
+
// implementation walked a clone calling `delete p[k]`, but walk() assigns its
|
|
116
|
+
// callback's result back over the child (`setprop(out, ckey, walk(...))`), so
|
|
117
|
+
// the delete was undone on the way out and the helper silently did nothing.
|
|
118
|
+
// Returning `undefined` from the callback does not fix it either: setprop
|
|
119
|
+
// stores undefined rather than removing the key, which then emits as a null.
|
|
120
|
+
//
|
|
121
|
+
// `dropDefaults` is opt-in and must be passed ONLY for the entity subtree.
|
|
122
|
+
// `active` means something different in feature config, where absent reads as
|
|
123
|
+
// INACTIVE (see feature_init) — dropping `active: true` there would silently
|
|
124
|
+
// disable the feature.
|
|
125
|
+
// jostraca's iteration metadata, injected by each()/names() while it walks the
|
|
126
|
+
// model. Listed explicitly rather than matched by trailing-dollar suffix: a
|
|
127
|
+
// trailing dollar is not exclusive to jostraca -- Seneca uses entity$ as real
|
|
128
|
+
// data -- so a blanket suffix match can silently drop a legitimate API field.
|
|
129
|
+
const MODEL_META = ['index$', 'key$', 'val$']
|
|
130
|
+
|
|
131
|
+
// Keys whose value IS the default the runtime already assumes when the key is
|
|
132
|
+
// absent, so emitting them is pure payload.
|
|
133
|
+
const CONFIG_DEFAULT: Record<string, any> = {
|
|
134
|
+
active: true,
|
|
135
|
+
req: false,
|
|
136
|
+
reqd: false,
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Subtrees carrying user payload rather than schema. An active:true inside an
|
|
140
|
+
// OpenAPI example is DATA, not a default, so default-pruning stops at these
|
|
141
|
+
// keys and everything below them is passed through untouched.
|
|
142
|
+
const PAYLOAD_KEYS = ['default', 'example', 'examples']
|
|
143
|
+
|
|
144
|
+
function clean(o: any, dropDefaults?: boolean): any {
|
|
145
|
+
const prune = (node: any, defaults: boolean): any => {
|
|
146
|
+
if (Array.isArray(node)) {
|
|
147
|
+
return node.map((n: any) => prune(n, defaults))
|
|
111
148
|
}
|
|
112
|
-
|
|
113
|
-
|
|
149
|
+
if (null != node && 'object' === typeof node) {
|
|
150
|
+
const out: any = {}
|
|
151
|
+
for (const k of Object.keys(node)) {
|
|
152
|
+
if (MODEL_META.includes(k)) {
|
|
153
|
+
continue
|
|
154
|
+
}
|
|
155
|
+
if (defaults && k in CONFIG_DEFAULT && CONFIG_DEFAULT[k] === node[k]) {
|
|
156
|
+
continue
|
|
157
|
+
}
|
|
158
|
+
out[k] = prune(node[k], defaults && !PAYLOAD_KEYS.includes(k))
|
|
159
|
+
}
|
|
160
|
+
return out
|
|
161
|
+
}
|
|
162
|
+
return node
|
|
163
|
+
}
|
|
164
|
+
return prune(o, true === dropDefaults)
|
|
114
165
|
}
|
|
115
166
|
|
|
116
167
|
|
|
@@ -77,13 +77,64 @@ function formatZigValue(val: any, indent: number = 0): string {
|
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
// Deep-remove meta keys (`foo$`) from a model subtree (twin of go's clean).
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
// Emission-time normalisation of a model subtree (L0).
|
|
81
|
+
//
|
|
82
|
+
// Always drops jostraca's iteration metadata (`$`-suffixed keys: index$,
|
|
83
|
+
// key$, val$). With `dropDefaults`, also drops keys whose value IS the
|
|
84
|
+
// default the runtime already assumes when the key is absent, which is pure
|
|
85
|
+
// payload — see CONFIG_DEFAULT.
|
|
86
|
+
//
|
|
87
|
+
// Rebuilds the tree rather than mutating during a walk. The previous
|
|
88
|
+
// implementation walked a clone calling `delete p[k]`, but walk() assigns its
|
|
89
|
+
// callback's result back over the child (`setprop(out, ckey, walk(...))`), so
|
|
90
|
+
// the delete was undone on the way out and the helper silently did nothing.
|
|
91
|
+
// Returning `undefined` from the callback does not fix it either: setprop
|
|
92
|
+
// stores undefined rather than removing the key, which then emits as a null.
|
|
93
|
+
//
|
|
94
|
+
// `dropDefaults` is opt-in and must be passed ONLY for the entity subtree.
|
|
95
|
+
// `active` means something different in feature config, where absent reads as
|
|
96
|
+
// INACTIVE (see feature_init) — dropping `active: true` there would silently
|
|
97
|
+
// disable the feature.
|
|
98
|
+
// jostraca's iteration metadata, injected by each()/names() while it walks the
|
|
99
|
+
// model. Listed explicitly rather than matched by trailing-dollar suffix: a
|
|
100
|
+
// trailing dollar is not exclusive to jostraca -- Seneca uses entity$ as real
|
|
101
|
+
// data -- so a blanket suffix match can silently drop a legitimate API field.
|
|
102
|
+
const MODEL_META = ['index$', 'key$', 'val$']
|
|
103
|
+
|
|
104
|
+
// Keys whose value IS the default the runtime already assumes when the key is
|
|
105
|
+
// absent, so emitting them is pure payload.
|
|
106
|
+
const CONFIG_DEFAULT: Record<string, any> = {
|
|
107
|
+
active: true,
|
|
108
|
+
req: false,
|
|
109
|
+
reqd: false,
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Subtrees carrying user payload rather than schema. An active:true inside an
|
|
113
|
+
// OpenAPI example is DATA, not a default, so default-pruning stops at these
|
|
114
|
+
// keys and everything below them is passed through untouched.
|
|
115
|
+
const PAYLOAD_KEYS = ['default', 'example', 'examples']
|
|
116
|
+
|
|
117
|
+
function clean(o: any, dropDefaults?: boolean): any {
|
|
118
|
+
const prune = (node: any, defaults: boolean): any => {
|
|
119
|
+
if (Array.isArray(node)) {
|
|
120
|
+
return node.map((n: any) => prune(n, defaults))
|
|
121
|
+
}
|
|
122
|
+
if (null != node && 'object' === typeof node) {
|
|
123
|
+
const out: any = {}
|
|
124
|
+
for (const k of Object.keys(node)) {
|
|
125
|
+
if (MODEL_META.includes(k)) {
|
|
126
|
+
continue
|
|
127
|
+
}
|
|
128
|
+
if (defaults && k in CONFIG_DEFAULT && CONFIG_DEFAULT[k] === node[k]) {
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
out[k] = prune(node[k], defaults && !PAYLOAD_KEYS.includes(k))
|
|
132
|
+
}
|
|
133
|
+
return out
|
|
84
134
|
}
|
|
85
|
-
return
|
|
86
|
-
}
|
|
135
|
+
return node
|
|
136
|
+
}
|
|
137
|
+
return prune(o, true === dropDefaults)
|
|
87
138
|
}
|
|
88
139
|
|
|
89
140
|
|
|
@@ -40,7 +40,8 @@ Point* point_new(voxgig_value* altmap) {
|
|
|
40
40
|
p->orig = dup_str(orig ? orig : "");
|
|
41
41
|
|
|
42
42
|
p->select = to_map(getp(altmap, "select"));
|
|
43
|
-
|
|
43
|
+
// Absent in config means ACTIVE: emission drops `active: true` as a default (sdkgen L0), so only an explicit `active: false` turns a point off.
|
|
44
|
+
bool active = true;
|
|
44
45
|
get_bool(altmap, "active", &active);
|
|
45
46
|
p->active = active;
|
|
46
47
|
p->relations = getp(altmap, "relations");
|
|
@@ -13,7 +13,9 @@ public class Point
|
|
|
13
13
|
public List<object?> Parts = new();
|
|
14
14
|
public List<object?>? Params;
|
|
15
15
|
public Dictionary<string, object?>? Select;
|
|
16
|
-
|
|
16
|
+
// Absent in config means ACTIVE: emission drops `active: true` as a
|
|
17
|
+
// default (sdkgen L0), so only an explicit `active: false` turns a point off.
|
|
18
|
+
public bool Active = true;
|
|
17
19
|
public List<object?>? Relations;
|
|
18
20
|
public Dictionary<string, object?> Alias = new();
|
|
19
21
|
public Dictionary<string, object?> Transform = new();
|
|
@@ -28,7 +28,8 @@ class Point {
|
|
|
28
28
|
parts = vs.getprop(altmap, 'parts', []);
|
|
29
29
|
params = vs.getprop(altmap, 'params', []);
|
|
30
30
|
select = vs.getprop(altmap, 'select');
|
|
31
|
-
active
|
|
31
|
+
// Absent in config means ACTIVE: emission drops `active: true` as a default (sdkgen L0), so only an explicit `active: false` turns a point off.
|
|
32
|
+
active = vs.getprop(altmap, 'active', true);
|
|
32
33
|
relations = vs.getprop(altmap, 'relations', []);
|
|
33
34
|
alias = vs.getprop(altmap, 'alias', {});
|
|
34
35
|
transform = vs.getprop(altmap, 'transform', {'req': null, 'res': null});
|
|
@@ -25,7 +25,7 @@ import (
|
|
|
25
25
|
|
|
26
26
|
// fhHasFeature is true when this SDK was generated with the named feature.
|
|
27
27
|
func fhHasFeature(name string) bool {
|
|
28
|
-
config := sdk.
|
|
28
|
+
config := sdk.SharedConfig()
|
|
29
29
|
fm, _ := config["feature"].(map[string]any)
|
|
30
30
|
return fm != nil && fm[name] != nil
|
|
31
31
|
}
|
|
@@ -127,7 +127,11 @@ func makeOptionsUtil(ctx *core.Context) map[string]any {
|
|
|
127
127
|
sysFetch = sf
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
// Clone the config side before merging: `config` is a process-wide
|
|
131
|
+
// singleton (see core.SharedConfig), and Merge would otherwise use its
|
|
132
|
+
// nested maps as merge TARGETS — one instance's options (server, headers,
|
|
133
|
+
// ...) would contaminate every instance constructed after it.
|
|
134
|
+
merged := vs.Merge([]any{map[string]any{}, vs.Clone(cfgopts), opts})
|
|
131
135
|
validated, _ := vs.Validate(merged, optspec)
|
|
132
136
|
opts = validated.(map[string]any)
|
|
133
137
|
|
|
@@ -18,7 +18,9 @@ public class Point {
|
|
|
18
18
|
public List<Object> parts = new ArrayList<>();
|
|
19
19
|
public List<Object> params;
|
|
20
20
|
public Map<String, Object> select;
|
|
21
|
-
|
|
21
|
+
// Absent in config means ACTIVE: emission drops `active: true` as a
|
|
22
|
+
// default (sdkgen L0), so only an explicit `active: false` turns a point off.
|
|
23
|
+
public boolean active = true;
|
|
22
24
|
public List<Object> relations;
|
|
23
25
|
public Map<String, Object> alias = new LinkedHashMap<>();
|
|
24
26
|
public Map<String, Object> transform = new LinkedHashMap<>();
|
|
@@ -16,7 +16,9 @@ class Point {
|
|
|
16
16
|
this.parts = getprop(altmap, 'parts', [])
|
|
17
17
|
this.params = getprop(altmap, 'params', [])
|
|
18
18
|
this.select = getprop(altmap, 'select')
|
|
19
|
-
|
|
19
|
+
// Absent in config means ACTIVE: emission drops `active: true` as a default
|
|
20
|
+
// (sdkgen L0), so only an explicit `active: false` turns a point off.
|
|
21
|
+
this.active = getprop(altmap, 'active', true)
|
|
20
22
|
this.relations = getprop(altmap, 'relations', [])
|
|
21
23
|
this.alias = getprop(altmap, 'alias', {})
|
|
22
24
|
this.transform = getprop(altmap, 'transform', { req: undefined, res: undefined })
|
|
@@ -13,7 +13,9 @@ class Point(pointmap: Map<String, Any?>?) {
|
|
|
13
13
|
var parts: MutableList<Any?> = mutableListOf()
|
|
14
14
|
var params: MutableList<Any?>? = null
|
|
15
15
|
var select: MutableMap<String, Any?>? = null
|
|
16
|
-
|
|
16
|
+
// Absent in config means ACTIVE: emission drops `active: true` as a
|
|
17
|
+
// default (sdkgen L0), so only an explicit `active: false` turns a point off.
|
|
18
|
+
var active: Boolean = true
|
|
17
19
|
var relations: MutableList<Any?>? = null
|
|
18
20
|
var alias: MutableMap<String, Any?> = linkedMapOf()
|
|
19
21
|
var transform: MutableMap<String, Any?> = linkedMapOf()
|
|
@@ -104,7 +104,11 @@ local function make_options_util(ctx)
|
|
|
104
104
|
-- Preserve system.fetch before merge/validate.
|
|
105
105
|
local sys_fetch = vs.getpath(opts, "system.fetch")
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
-- Clone the config side before merging: `config` is a per-Lua-state
|
|
108
|
+
-- singleton (see config_shared), and merge would otherwise use its nested
|
|
109
|
+
-- tables as merge TARGETS — one instance's options (server, headers, ...)
|
|
110
|
+
-- would contaminate every instance constructed after it.
|
|
111
|
+
local merged = vs.merge({ {}, vs.clone(cfgopts), opts })
|
|
108
112
|
local validated = vs.validate(merged, optspec)
|
|
109
113
|
if type(validated) ~= "table" then
|
|
110
114
|
validated = {}
|
|
@@ -149,7 +149,7 @@ class FtHarness
|
|
|
149
149
|
public static function hasFeature(string $name): bool
|
|
150
150
|
{
|
|
151
151
|
if (self::$feature_config === null) {
|
|
152
|
-
$config = ProjectNameConfig::
|
|
152
|
+
$config = ProjectNameConfig::shared_config();
|
|
153
153
|
$f = $config['feature'] ?? [];
|
|
154
154
|
self::$feature_config = is_array($f) ? $f : [];
|
|
155
155
|
}
|
|
@@ -96,7 +96,11 @@ def make_options_util(ctx):
|
|
|
96
96
|
# Preserve system.fetch before merge/validate.
|
|
97
97
|
sys_fetch = vs.getpath(opts, "system.fetch")
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
# Clone the config side before merging: `config` is a process-wide
|
|
100
|
+
# singleton (see config.shared_config), and merge would otherwise use its
|
|
101
|
+
# nested dicts as merge TARGETS — one instance's options (server, headers,
|
|
102
|
+
# ...) would contaminate every instance constructed after it.
|
|
103
|
+
merged = vs.merge([{}, vs.clone(cfgopts), opts])
|
|
100
104
|
validated = vs.validate(merged, optspec)
|
|
101
105
|
if not isinstance(validated, dict):
|
|
102
106
|
validated = {}
|
|
@@ -14,7 +14,7 @@ from __future__ import annotations
|
|
|
14
14
|
|
|
15
15
|
from urllib.parse import quote
|
|
16
16
|
|
|
17
|
-
from projectname_sdk.config import
|
|
17
|
+
from projectname_sdk.config import shared_config
|
|
18
18
|
from projectname_sdk.features import _make_feature
|
|
19
19
|
from projectname_sdk.core.control import ProjectNameControl
|
|
20
20
|
from projectname_sdk.core.error import ProjectNameError
|
|
@@ -24,7 +24,7 @@ from projectname_sdk.core.spec import ProjectNameSpec
|
|
|
24
24
|
|
|
25
25
|
# True when this SDK was generated with the named feature.
|
|
26
26
|
def has_feature(name):
|
|
27
|
-
feature =
|
|
27
|
+
feature = shared_config().get("feature")
|
|
28
28
|
return isinstance(feature, dict) and feature.get(name) is not None
|
|
29
29
|
|
|
30
30
|
|
|
@@ -15,7 +15,7 @@ require_relative "../ProjectName_sdk"
|
|
|
15
15
|
module ProjectNameFeatureHarness
|
|
16
16
|
# True when this SDK was generated with the named feature.
|
|
17
17
|
def self.has_feature?(name)
|
|
18
|
-
f = ProjectNameConfig.
|
|
18
|
+
f = ProjectNameConfig.shared_config["feature"]
|
|
19
19
|
f.is_a?(Hash) && !f[name].nil?
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -61,7 +61,11 @@ module ProjectNameUtilities
|
|
|
61
61
|
|
|
62
62
|
sys_fetch = VoxgigStruct.getpath(opts, "system.fetch")
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
# Clone the config side before merging: `config` is a process-wide
|
|
65
|
+
# singleton (see Config.shared_config), and merge would otherwise use its
|
|
66
|
+
# nested hashes as merge TARGETS — one instance's options (server,
|
|
67
|
+
# headers, ...) would contaminate every instance constructed after it.
|
|
68
|
+
merged = VoxgigStruct.merge([{}, VoxgigStruct.clone(cfgopts), opts])
|
|
65
69
|
validated = VoxgigStruct.validate(merged, optspec)
|
|
66
70
|
opts = validated.is_a?(Hash) ? validated : {}
|
|
67
71
|
|
|
@@ -13,7 +13,8 @@ class Point(pointmap: JMap[String, Object]) {
|
|
|
13
13
|
var parts: JList[Object] = new ArrayList[Object]()
|
|
14
14
|
var params: JList[Object] = null
|
|
15
15
|
var select: JMap[String, Object] = null
|
|
16
|
-
|
|
16
|
+
// Absent in config means ACTIVE: emission drops `active: true` as a default (sdkgen L0), so only an explicit `active: false` turns a point off.
|
|
17
|
+
var active: Boolean = true
|
|
17
18
|
var relations: JList[Object] = null
|
|
18
19
|
var alias: JMap[String, Object] = new LinkedHashMap[String, Object]()
|
|
19
20
|
var transform: JMap[String, Object] = new LinkedHashMap[String, Object]()
|
|
@@ -10,7 +10,9 @@ public final class Point {
|
|
|
10
10
|
public var parts: VList = VList()
|
|
11
11
|
public var params: VList? = nil
|
|
12
12
|
public var select: VMap? = nil
|
|
13
|
-
|
|
13
|
+
// Absent in config means ACTIVE: emission drops `active: true` as a
|
|
14
|
+
// default (sdkgen L0), so only an explicit `active: false` turns a point off.
|
|
15
|
+
public var active: Bool = true
|
|
14
16
|
public var relations: VList? = nil
|
|
15
17
|
public var alias: VMap = VMap()
|
|
16
18
|
public var transform: VMap = VMap()
|
|
@@ -30,7 +30,9 @@ class Point {
|
|
|
30
30
|
this.parts = getprop(altmap, 'parts', [])
|
|
31
31
|
this.params = getprop(altmap, 'params', [])
|
|
32
32
|
this.select = getprop(altmap, 'select')
|
|
33
|
-
|
|
33
|
+
// Absent in config means ACTIVE: emission drops `active: true` as a default
|
|
34
|
+
// (sdkgen L0), so only an explicit `active: false` turns a point off.
|
|
35
|
+
this.active = getprop(altmap, 'active', true)
|
|
34
36
|
this.relations = getprop(altmap, 'relations', [])
|
|
35
37
|
this.alias = getprop(altmap, 'alias', {})
|
|
36
38
|
this.transform = getprop(altmap, 'transform', { req: undefined, res: undefined })
|
|
@@ -12,7 +12,8 @@ pub const Point = struct {
|
|
|
12
12
|
parts: Value,
|
|
13
13
|
params: Value,
|
|
14
14
|
select: Value,
|
|
15
|
-
active:
|
|
15
|
+
// Absent in config means ACTIVE: emission drops `active: true` as a default (sdkgen L0), so only an explicit `active: false` turns a point off.
|
|
16
|
+
active: bool = true,
|
|
16
17
|
relations: Value,
|
|
17
18
|
alias: Value,
|
|
18
19
|
transform: Value,
|
package/src/cmp/Readme.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { ReadmeErrors } from './ReadmeErrors'
|
|
|
9
9
|
import { ReadmeModel } from './ReadmeModel'
|
|
10
10
|
import { ReadmeOptions } from './ReadmeOptions'
|
|
11
11
|
import { ReadmeEntity } from './ReadmeEntity'
|
|
12
|
+
import { ReadmeUnions } from './ReadmeUnions'
|
|
12
13
|
import { ReadmeHowto } from './ReadmeHowto'
|
|
13
14
|
import { ReadmeExplanation } from './ReadmeExplanation'
|
|
14
15
|
import { ReadmeRef } from './ReadmeRef'
|
|
@@ -28,6 +29,7 @@ const Readme = cmp(function Readme(props: any) {
|
|
|
28
29
|
ReadmeModel({ target })
|
|
29
30
|
ReadmeOptions({ target })
|
|
30
31
|
ReadmeEntity({ target })
|
|
32
|
+
ReadmeUnions({ target })
|
|
31
33
|
ReadmeExplanation({ target })
|
|
32
34
|
|
|
33
35
|
Content(`
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { cmp, each, Content } from 'jostraca'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
KIT,
|
|
5
|
+
getModelPath
|
|
6
|
+
} from '../types'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
// Fields whose type could not be narrowed because the API definition describes
|
|
10
|
+
// them with an UNTAGGED union: `oneOf`/`anyOf` branches carrying no
|
|
11
|
+
// `discriminator`, so the specification never states which variant a given
|
|
12
|
+
// value is. apidef records the widest such union it finds beneath each field
|
|
13
|
+
// (see ModelField.union); this section reports them.
|
|
14
|
+
//
|
|
15
|
+
// Without this, those fields read as a modelling failure — a `groups` field
|
|
16
|
+
// typed as a bare array looks like the generator gave up, when in fact the
|
|
17
|
+
// definition offers nothing to narrow it to. Saying so is the difference
|
|
18
|
+
// between an SDK that looks unfinished and one that documents the API it was
|
|
19
|
+
// given.
|
|
20
|
+
//
|
|
21
|
+
// Two-branch unions are NOT reported: `oneOf: [string, number]` is a routine
|
|
22
|
+
// either/or, an open type for it surprises nobody, and listing every one would
|
|
23
|
+
// bury the cases that matter.
|
|
24
|
+
const MIN_REPORTED_BRANCHES = 3
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
const ReadmeUnions = cmp(function ReadmeUnions(props: any) {
|
|
28
|
+
const { ctx$ } = props
|
|
29
|
+
const { model } = ctx$
|
|
30
|
+
|
|
31
|
+
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
32
|
+
|
|
33
|
+
const rows: { entity: string, field: string, branches: number, depth: number }[] = []
|
|
34
|
+
|
|
35
|
+
each(entity, (ent: any) => {
|
|
36
|
+
if (false === ent.active) {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
each(ent.fields, (field: any) => {
|
|
40
|
+
const union = field?.union
|
|
41
|
+
if (null == union || union.branches < MIN_REPORTED_BRANCHES) {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
rows.push({
|
|
45
|
+
entity: ent.name,
|
|
46
|
+
field: field.name,
|
|
47
|
+
branches: union.branches,
|
|
48
|
+
depth: union.depth,
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
if (0 === rows.length) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Widest first: the worst offender is the one a reader needs to see.
|
|
58
|
+
rows.sort((a, b) => b.branches - a.branches || a.entity.localeCompare(b.entity) ||
|
|
59
|
+
a.field.localeCompare(b.field))
|
|
60
|
+
|
|
61
|
+
const plural = 1 === rows.length ? 'field is' : 'fields are'
|
|
62
|
+
|
|
63
|
+
Content(`
|
|
64
|
+
## Open types
|
|
65
|
+
|
|
66
|
+
${rows.length} ${plural} carried as open values rather than typed structures.
|
|
67
|
+
This follows from the API definition, not from a gap in this SDK: the
|
|
68
|
+
definition describes ${1 === rows.length ? 'it' : 'them'} with untagged unions —
|
|
69
|
+
\`oneOf\`/\`anyOf\` branches with no \`discriminator\` — so it never states which
|
|
70
|
+
variant a given value is. Nothing can select a branch reliably, so the SDK
|
|
71
|
+
passes the value through unchanged rather than assert a shape the API does not
|
|
72
|
+
guarantee.
|
|
73
|
+
|
|
74
|
+
| Entity | Field | Variants | Nesting |
|
|
75
|
+
| --- | --- | --- | --- |
|
|
76
|
+
${rows.map((r) =>
|
|
77
|
+
`| \`${r.entity}\` | \`${r.field}\` | ${r.branches} | ` +
|
|
78
|
+
`${r.depth} ${1 === r.depth ? 'level' : 'levels'} |`).join('\n')}
|
|
79
|
+
|
|
80
|
+
These values round-trip unchanged — read them, modify them, send them back. If
|
|
81
|
+
the API adds a \`discriminator\` to the definition, regenerating will type them.
|
|
82
|
+
Every other field is typed normally.
|
|
83
|
+
`)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
export {
|
|
88
|
+
ReadmeUnions,
|
|
89
|
+
MIN_REPORTED_BRANCHES,
|
|
90
|
+
}
|