@voxgig/sdkgen 4.5.3 → 4.6.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/bin/voxgig-sdkgen +1 -1
- package/dist/action/check.js +15 -0
- package/dist/action/check.js.map +1 -1
- package/dist/cmp/AgentGuide.js +1 -1
- package/dist/cmp/AgentGuide.js.map +1 -1
- package/dist/cmp/AgentGuideContent.d.ts +1 -1
- package/dist/cmp/AgentGuideContent.js +8 -2
- package/dist/cmp/AgentGuideContent.js.map +1 -1
- package/dist/cmp/Feature.js +17 -0
- package/dist/cmp/Feature.js.map +1 -1
- package/dist/cmp/FeatureDocs.d.ts +1 -1
- package/dist/cmp/FeatureDocs.js +6 -1
- package/dist/cmp/FeatureDocs.js.map +1 -1
- package/dist/cmp/ReadmeExplanation.js +3 -1
- package/dist/cmp/ReadmeExplanation.js.map +1 -1
- package/dist/cmp/ReadmeFeatures.js +1 -1
- package/dist/cmp/ReadmeFeatures.js.map +1 -1
- package/dist/cmp/ReadmeRefFeatures.js +1 -1
- package/dist/cmp/ReadmeRefFeatures.js.map +1 -1
- package/dist/helpers/applicability.d.ts +6 -0
- package/dist/helpers/applicability.js +103 -0
- package/dist/helpers/applicability.js.map +1 -0
- package/dist/helpers/collectDeps.js +4 -2
- package/dist/helpers/collectDeps.js.map +1 -1
- package/dist/helpers/serverVars.d.ts +2 -1
- package/dist/helpers/serverVars.js +17 -0
- package/dist/helpers/serverVars.js.map +1 -1
- package/dist/sdkgen.d.ts +3 -2
- package/dist/sdkgen.js +9 -2
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.js +7 -1
- package/dist/utility.js.map +1 -1
- package/model/sdkgen.aon +39 -0
- package/package.json +1 -1
- package/project/.sdk/model/feature/feature-index.aon +1 -0
- package/project/.sdk/model/feature/secrets.aon +118 -0
- package/project/.sdk/model/target/ts.aon +8 -1
- package/project/.sdk/src/cmp/c/Config_c.ts +5 -1
- package/project/.sdk/src/cmp/cpp/Config_cpp.ts +5 -1
- package/project/.sdk/src/cmp/csharp/Config_csharp.ts +5 -1
- package/project/.sdk/src/cmp/dart/Config_dart.ts +5 -1
- package/project/.sdk/src/cmp/elixir/Config_elixir.ts +5 -1
- package/project/.sdk/src/cmp/elixir/Main_elixir.ts +5 -1
- package/project/.sdk/src/cmp/go/Config_go.ts +5 -1
- package/project/.sdk/src/cmp/go/Main_go.ts +6 -2
- package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +16 -3
- package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +16 -3
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +28 -4
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +43 -10
- package/project/.sdk/src/cmp/go/fragment/Main.fragment.go +5 -5
- package/project/.sdk/src/cmp/java/Config_java.ts +22 -1
- package/project/.sdk/src/cmp/java/Main_java.ts +5 -1
- package/project/.sdk/src/cmp/java/ReadmeQuick_java.ts +17 -3
- package/project/.sdk/src/cmp/java/ReadmeTopQuick_java.ts +17 -3
- package/project/.sdk/src/cmp/java/TestDirect_java.ts +23 -4
- package/project/.sdk/src/cmp/java/TestEntity_java.ts +29 -4
- package/project/.sdk/src/cmp/js/Config_js.ts +5 -1
- package/project/.sdk/src/cmp/js/Main_js.ts +5 -1
- package/project/.sdk/src/cmp/js/Package_js.ts +4 -1
- package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +5 -1
- package/project/.sdk/src/cmp/lean/Config_lean.ts +5 -1
- package/project/.sdk/src/cmp/lua/Config_lua.ts +5 -1
- package/project/.sdk/src/cmp/lua/Main_lua.ts +5 -1
- package/project/.sdk/src/cmp/lua/Package_lua.ts +4 -1
- package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +5 -1
- package/project/.sdk/src/cmp/perl/Main_perl.ts +5 -1
- package/project/.sdk/src/cmp/php/Config_php.ts +5 -1
- package/project/.sdk/src/cmp/php/Main_php.ts +5 -1
- package/project/.sdk/src/cmp/py/Config_py.ts +5 -1
- package/project/.sdk/src/cmp/py/Main_py.ts +5 -1
- package/project/.sdk/src/cmp/py/ReadmeQuick_py.ts +16 -3
- package/project/.sdk/src/cmp/py/ReadmeTopQuick_py.ts +16 -3
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +24 -5
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +23 -3
- package/project/.sdk/src/cmp/rb/Config_rb.ts +5 -1
- package/project/.sdk/src/cmp/rb/Main_rb.ts +5 -1
- package/project/.sdk/src/cmp/rust/Config_rust.ts +5 -1
- package/project/.sdk/src/cmp/rust/Main_rust.ts +5 -1
- package/project/.sdk/src/cmp/scala/Config_scala.ts +5 -1
- package/project/.sdk/src/cmp/scala/Main_scala.ts +5 -1
- package/project/.sdk/src/cmp/swift/Config_swift.ts +5 -1
- package/project/.sdk/src/cmp/ts/Config_ts.ts +5 -1
- package/project/.sdk/src/cmp/ts/Main_ts.ts +57 -1
- package/project/.sdk/src/cmp/ts/Package_ts.ts +4 -1
- package/project/.sdk/src/cmp/ts/ReadmeModel_ts.ts +15 -3
- package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +18 -5
- package/project/.sdk/src/cmp/ts/ReadmeTopQuick_ts.ts +19 -5
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +67 -7
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +27 -4
- package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +9 -2
- package/project/.sdk/src/cmp/ts/fragment/Entity.test.fragment.ts +9 -2
- package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +7 -0
- package/project/.sdk/src/cmp/zig/Config_zig.ts +5 -1
- package/project/.sdk/tm/c/utility/make_options.c +22 -0
- package/project/.sdk/tm/clojure/src/sdk/core.clj +18 -1
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +23 -0
- package/project/.sdk/tm/csharp/test/CustomUtilityTest.cs +15 -0
- package/project/.sdk/tm/csharp/utility/MakeOptions.cs +23 -0
- package/project/.sdk/tm/dart/lib/utility/MakeOptionsUtility.dart +22 -0
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +19 -0
- package/project/.sdk/tm/go/core/context.go +1 -1
- package/project/.sdk/tm/go/feature/cost_feature.go +1 -1
- package/project/.sdk/tm/go/feature/paging_feature.go +5 -5
- package/project/.sdk/tm/go/feature/test_feature.go +12 -5
- package/project/.sdk/tm/go/test/custom_utility_test.go +15 -0
- package/project/.sdk/tm/go/test/feature_corpus_test.go +7 -0
- package/project/.sdk/tm/go/test/runner_test.go +46 -0
- package/project/.sdk/tm/go/test/struct_runner_test.go +7 -7
- package/project/.sdk/tm/go/test/struct_utility_test.go +63 -27
- package/project/.sdk/tm/go/utility/fetcher.go +2 -2
- package/project/.sdk/tm/go/utility/make_options.go +24 -5
- package/project/.sdk/tm/go/utility/make_point.go +1 -1
- package/project/.sdk/tm/go/utility/make_spec.go +17 -1
- package/project/.sdk/tm/go/utility/prepare_auth.go +1 -1
- package/project/.sdk/tm/go/utility/struct/voxgigstruct.go +370 -307
- package/project/.sdk/tm/go/utility/transform_request.go +29 -1
- package/project/.sdk/tm/go/utility/transform_response.go +20 -1
- package/project/.sdk/tm/java/test/CustomUtilityTest.java +10 -0
- package/project/.sdk/tm/java/test/FeatureCorpusTest.java +7 -0
- package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +6 -0
- package/project/.sdk/tm/java/test/RunnerSupport.java +43 -0
- package/project/.sdk/tm/java/utility/MakeOptions.java +84 -1
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +24 -0
- package/project/.sdk/tm/js/src/utility/StructUtility.js +2076 -1837
- package/project/.sdk/tm/js/test/feature/Corpus.test.js +9 -0
- package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +21 -0
- package/project/.sdk/tm/lean/src/SdkUtility.lean +12 -1
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +11 -0
- package/project/.sdk/tm/perl/utility/make_options.pm +18 -0
- package/project/.sdk/tm/php/test/FeatureCorpusTest.php +10 -1
- package/project/.sdk/tm/php/utility/MakeOptions.php +24 -0
- package/project/.sdk/tm/py/pkg/utility/make_options.py +20 -0
- package/project/.sdk/tm/py/test/runner.py +32 -0
- package/project/.sdk/tm/py/test/test_feature_corpus.py +10 -1
- package/project/.sdk/tm/rb/test/feature_corpus_test.rb +9 -1
- package/project/.sdk/tm/rb/utility/make_options.rb +17 -0
- package/project/.sdk/tm/rust/utility/make_options.rs +25 -0
- package/project/.sdk/tm/scala/utility/Make.scala +17 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +21 -0
- package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +419 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Providers.ts +1221 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sekreto.ts +381 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sigv4.ts +151 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/index.ts +42 -0
- package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +18 -0
- package/project/.sdk/tm/ts/src/utility/StructUtility.ts +1321 -710
- package/project/.sdk/tm/ts/test/feature/Corpus.test.ts +9 -0
- package/project/.sdk/tm/ts/test/feature/secrets/Secrets.test.ts +764 -0
- package/project/.sdk/tm/ts/test/omni.test.ts +84 -0
- package/project/.sdk/tm/ts/test/omni.ts +86 -0
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +6 -2
- package/project/.sdk/tm/ts/test/utility/StructUtility.test.ts +2 -2
- package/project/.sdk/tm/ts/test/utility.ts +122 -0
- package/project/.sdk/tm/ts/test/vendor/omni/Runner.ts +692 -0
- package/project/.sdk/tm/ts/test/vendor/omni/Util.ts +238 -0
- package/project/.sdk/tm/ts/test/vendor/omni/compat.ts +188 -0
- package/project/.sdk/tm/ts/test/vendor/omni/index.ts +38 -0
- package/project/.sdk/tm/zig/core/utility.zig +23 -0
- package/project/sdkgen-package.json +2 -1
- package/src/action/check.ts +18 -0
- package/src/cmp/AgentGuide.ts +1 -1
- package/src/cmp/AgentGuideContent.ts +9 -2
- package/src/cmp/Feature.ts +19 -0
- package/src/cmp/FeatureDocs.ts +7 -1
- package/src/cmp/ReadmeExplanation.ts +4 -1
- package/src/cmp/ReadmeFeatures.ts +1 -1
- package/src/cmp/ReadmeRefFeatures.ts +1 -1
- package/src/helpers/applicability.ts +123 -0
- package/src/helpers/collectDeps.ts +5 -1
- package/src/helpers/serverVars.ts +19 -0
- package/src/sdkgen.ts +9 -1
- package/src/utility.ts +10 -1
- package/project/.sdk/tm/ts/test/runner.ts +0 -425
package/model/sdkgen.aon
CHANGED
|
@@ -172,6 +172,27 @@ main: kit: target: &: {
|
|
|
172
172
|
ext: string
|
|
173
173
|
comment: line: string
|
|
174
174
|
|
|
175
|
+
# APPLICABILITY (docs/design/feature-tags.md). What this target can offer
|
|
176
|
+
# a feature; a feature applies here when its `needs` is a subset of this.
|
|
177
|
+
# Empty is the default, so a target says nothing until it has a reason to.
|
|
178
|
+
#
|
|
179
|
+
# THE VOCABULARY IS CLOSED — extended by editing this comment and the
|
|
180
|
+
# schema, never by a package inventing a string. Two authors spelling the
|
|
181
|
+
# same capability differently is the whole failure mode a free-form tag
|
|
182
|
+
# would reintroduce.
|
|
183
|
+
#
|
|
184
|
+
# sekreto a vendored sekreto port lives in this target's feature
|
|
185
|
+
# container, so a feature can resolve secrets through it
|
|
186
|
+
#
|
|
187
|
+
# Tags named in the design note but not yet load-bearing
|
|
188
|
+
# (`per-feature-file`, `deps`, `transport-wrap`, `hooks`, `delegates`)
|
|
189
|
+
# are deliberately absent until a feature actually gates on one: a tag
|
|
190
|
+
# whose answer is currently "everyone" buys nothing and has to be kept
|
|
191
|
+
# true across 27 targets.
|
|
192
|
+
#
|
|
193
|
+
# A map keyed by tag, matching `needs` — see the note there.
|
|
194
|
+
provides: &: boolean
|
|
195
|
+
|
|
175
196
|
base: *'' | string
|
|
176
197
|
origname: *'' | string
|
|
177
198
|
package: *'' | string
|
|
@@ -420,6 +441,24 @@ main: kit: feature: &: {
|
|
|
420
441
|
# TODO: version '0.0.1' | semver # where semver is a string format type as per semver.org
|
|
421
442
|
version: *'0.0.1' | string
|
|
422
443
|
|
|
444
|
+
# APPLICABILITY (docs/design/feature-tags.md). What this feature requires
|
|
445
|
+
# of a target; it applies where `needs` is a subset of the target's
|
|
446
|
+
# `provides`. Empty means "applies anywhere", so every feature that
|
|
447
|
+
# predates the gate is unaffected — the gate is additive by construction.
|
|
448
|
+
#
|
|
449
|
+
# A tag, not a target list: a list has to be edited for targets the
|
|
450
|
+
# feature's author has never heard of, so a published package would
|
|
451
|
+
# starve every target added after its release.
|
|
452
|
+
#
|
|
453
|
+
# The vocabulary is closed and lives in `main: kit: target: &: provides`.
|
|
454
|
+
#
|
|
455
|
+
# A MAP keyed by tag, not a list, for the reason `contributor` is a map:
|
|
456
|
+
# aontu unifies maps by key, so a package can add one tag without
|
|
457
|
+
# restating the others. A list here also hangs the unifier outright on a
|
|
458
|
+
# real project's model (a defaulted list disjunction under this spread),
|
|
459
|
+
# which is what settled the shape.
|
|
460
|
+
needs: &: boolean
|
|
461
|
+
|
|
423
462
|
# Transport role (station design §8.4): how the feature relates to the
|
|
424
463
|
# transport slot. 'base' REPLACES ctx.utility.fetcher outright (only the
|
|
425
464
|
# `test` feature); 'wrap' wraps it in init() (netsim, retry, cache,
|
package/package.json
CHANGED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
|
|
2
|
+
main: kit: feature: secrets: {
|
|
3
|
+
|
|
4
|
+
name: key()
|
|
5
|
+
title: "Secret access: resolve the API credential through a provider chain, and exchange a refresh token for short-lived access tokens"
|
|
6
|
+
version: '0.1.0'
|
|
7
|
+
base: 'BASE'
|
|
8
|
+
|
|
9
|
+
# `active` is deliberately NOT set here. The base schema defaults it
|
|
10
|
+
# (`active: *false | boolean`), and in aontu a concrete value does not
|
|
11
|
+
# yield to another concrete value — it CONFLICTS. Restating `active:
|
|
12
|
+
# false` here would make a project's `main: kit: feature: secrets:
|
|
13
|
+
# active: true` fail to unify, which is the same defect the publication
|
|
14
|
+
# keys carry a warning about in model/target/ts.aon.
|
|
15
|
+
#
|
|
16
|
+
# So the feature is OFF until a project turns it on, in its own overlay
|
|
17
|
+
# (model/project.aon), which `feature add` never overwrites.
|
|
18
|
+
|
|
19
|
+
# Applicability (docs/design/feature-tags.md). The feature is a thin
|
|
20
|
+
# layer over a VENDORED sekreto port, so it only applies to a target
|
|
21
|
+
# whose feature container carries one. Without this tag the feature
|
|
22
|
+
# would fan out to every target, and each one that generated would
|
|
23
|
+
# carry an import for a class it has no source for.
|
|
24
|
+
needs: { sekreto: true }
|
|
25
|
+
|
|
26
|
+
# Transport role (station design §8.4).
|
|
27
|
+
#
|
|
28
|
+
# 'wrap', because the access-token exchange below has to SEE the response:
|
|
29
|
+
# a spent token is discovered by the API answering 401, and the only place
|
|
30
|
+
# to notice that and try again is around the transport. It wraps only when
|
|
31
|
+
# `exchange.active` — with the exchange off this feature never touches the
|
|
32
|
+
# transport, exactly as when its role was 'none' — but the role is a
|
|
33
|
+
# DECLARATION of what the feature may do, not a report of what one
|
|
34
|
+
# configuration does, so it is declared at its widest.
|
|
35
|
+
transport: 'wrap'
|
|
36
|
+
|
|
37
|
+
config: {
|
|
38
|
+
options: {
|
|
39
|
+
active: false
|
|
40
|
+
|
|
41
|
+
# The sekreto provider chain, in first-hit order. Each entry is a
|
|
42
|
+
# sekreto ProviderSpec ({ kind, name, ... }) or a provider object.
|
|
43
|
+
# An explicit `apikey` option, when set, is placed AHEAD of these as
|
|
44
|
+
# a `memory` store named 'options', so an explicit credential still
|
|
45
|
+
# wins — by sekreto's own first-hit rule, not by special-casing.
|
|
46
|
+
providers: []
|
|
47
|
+
|
|
48
|
+
# The secret to resolve, for an API whose credential is not
|
|
49
|
+
# apikey-shaped. The resolved value is written to options.apikey
|
|
50
|
+
# regardless, because that is where prepareAuth looks.
|
|
51
|
+
name: 'apikey'
|
|
52
|
+
|
|
53
|
+
# sekreto caches resolved values by default. Off means every
|
|
54
|
+
# resolve() asks the chain again; redaction still tracks values.
|
|
55
|
+
cache: true
|
|
56
|
+
|
|
57
|
+
# ACCESS-TOKEN EXCHANGE (the OAuth2 refresh grant, in miniature).
|
|
58
|
+
#
|
|
59
|
+
# Some APIs do not accept a long-lived credential at all: the secret the
|
|
60
|
+
# chain above resolves is a REFRESH token, which buys a short-lived ACCESS
|
|
61
|
+
# token from a token endpoint, and that access token is what every request
|
|
62
|
+
# carries. The access token then expires, and the client is expected to buy
|
|
63
|
+
# another without human help.
|
|
64
|
+
#
|
|
65
|
+
# Off by default, and inert when off: with `exchange.active: false` this
|
|
66
|
+
# feature behaves exactly as it always did — resolve one secret, write it to
|
|
67
|
+
# options.apikey. That is what keeps the change additive for every SDK
|
|
68
|
+
# already using it.
|
|
69
|
+
#
|
|
70
|
+
# With it on, set `name` to the refresh secret (`name: 'refresh_token'`),
|
|
71
|
+
# because `name` is what the chain is asked for.
|
|
72
|
+
exchange: {
|
|
73
|
+
active: false
|
|
74
|
+
|
|
75
|
+
# The token endpoint, RELATIVE to options.base — the base already
|
|
76
|
+
# carries whatever account or tenant segment the server URL declares,
|
|
77
|
+
# so a relative path follows it without being told about it.
|
|
78
|
+
path: 'auth/token'
|
|
79
|
+
method: 'POST'
|
|
80
|
+
|
|
81
|
+
# The JSON field the refresh credential is SENT in, and the field the
|
|
82
|
+
# access token comes back in. Named rather than assumed: `access_token`
|
|
83
|
+
# and `refresh_token` are the OAuth2 spelling, and plenty of APIs use
|
|
84
|
+
# their own.
|
|
85
|
+
request: 'refresh_token'
|
|
86
|
+
response: 'access_token'
|
|
87
|
+
|
|
88
|
+
# An explicit refresh token, given in code. It becomes the FIRST
|
|
89
|
+
# provider in the chain, so it wins by sekreto's own first-hit rule —
|
|
90
|
+
# the same seat `options.apikey` takes when no exchange is configured.
|
|
91
|
+
# `options.apikey` cannot serve here: with an exchange configured it
|
|
92
|
+
# means "an access token I already hold", which is the opposite kind
|
|
93
|
+
# of credential.
|
|
94
|
+
refresh: ''
|
|
95
|
+
|
|
96
|
+
# Response statuses that mean "your access token is spent, buy
|
|
97
|
+
# another". 401 is the answer every API in this shape gives; 403 is
|
|
98
|
+
# listed by some, so it is configurable rather than assumed.
|
|
99
|
+
statuses: [401]
|
|
100
|
+
|
|
101
|
+
# How many times ONE request may buy a token and try again. One is
|
|
102
|
+
# right: a second refusal on a token bought moments ago is a real
|
|
103
|
+
# failure — a revoked refresh token, the wrong account — and retrying
|
|
104
|
+
# it turns that into a spin instead of an error.
|
|
105
|
+
retries: 1
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# Resolution is ASYNC (a provider may do IO, and the exchange makes an
|
|
111
|
+
# HTTP request) but prepareAuth is sync.
|
|
112
|
+
# Entity ops await featureHook('PreSpec') before makeSpec, so this is
|
|
113
|
+
# the one seam where the lookup can happen and still land in time.
|
|
114
|
+
# Concurrent operations share the single in-flight promise.
|
|
115
|
+
hook: {
|
|
116
|
+
PreSpec: { active: true, await: true }
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -7,13 +7,20 @@ main: kit: target: ts: {
|
|
|
7
7
|
module: name: '$$name$$'
|
|
8
8
|
base: 'BASE'
|
|
9
9
|
|
|
10
|
+
# Applicability (docs/design/feature-tags.md). A vendored sekreto port
|
|
11
|
+
# lives in this target's feature container, so a feature that resolves
|
|
12
|
+
# secrets through sekreto can apply here.
|
|
13
|
+
provides: { sekreto: true }
|
|
14
|
+
|
|
10
15
|
deps: &: {
|
|
11
16
|
# TODO: fix aontu disjunctions!
|
|
12
17
|
kind: *'prod' | string # 'peer' |'dev'
|
|
13
18
|
}
|
|
14
19
|
|
|
15
20
|
deps: {
|
|
16
|
-
|
|
21
|
+
# dotenv was dropped when the generated entity tests moved to
|
|
22
|
+
# `loadEnvLocal` (tm/ts/test/utility.ts) — the SDK's last non-tooling
|
|
23
|
+
# dependency of any kind.
|
|
17
24
|
'typescript': { active: true, version: '^5.9.3', kind: dev }
|
|
18
25
|
'@types/node': { active: true, version: '^25.6.0', kind: dev }
|
|
19
26
|
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
isAuthActive,
|
|
10
10
|
isConfigData,
|
|
11
11
|
resolveAuthPrefix,
|
|
12
|
+
targetFeatures,
|
|
12
13
|
} from '@voxgig/sdkgen'
|
|
13
14
|
|
|
14
15
|
|
|
@@ -36,7 +37,10 @@ const Config = cmp(async function Config(props: any) {
|
|
|
36
37
|
const model: Model = ctx$.model
|
|
37
38
|
|
|
38
39
|
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
39
|
-
|
|
40
|
+
// Gated by the applicability tags, so this target never imports or
|
|
41
|
+
// registers a feature it has no source for. One rule, one place:
|
|
42
|
+
// helpers/applicability.
|
|
43
|
+
const feature = targetFeatures(model, target)
|
|
40
44
|
|
|
41
45
|
const headers = getModelPath(model, `main.${KIT}.config.headers`) || {}
|
|
42
46
|
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
cmp,
|
|
6
6
|
configDefinition,
|
|
7
7
|
each,
|
|
8
|
+
targetFeatures,
|
|
8
9
|
} from '@voxgig/sdkgen'
|
|
9
10
|
|
|
10
11
|
|
|
@@ -30,7 +31,10 @@ const Config = cmp(async function Config(props: any) {
|
|
|
30
31
|
|
|
31
32
|
const model: Model = ctx$.model
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
// Gated by the applicability tags, so this target never imports or
|
|
35
|
+
// registers a feature it has no source for. One rule, one place:
|
|
36
|
+
// helpers/applicability.
|
|
37
|
+
const feature = targetFeatures(model, target)
|
|
34
38
|
|
|
35
39
|
// The embedded config, built by the shared helper so this target's shapes
|
|
36
40
|
// and identity fields stay in step with the ts reference by construction.
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
configReprSetting,
|
|
8
8
|
each,
|
|
9
9
|
isConfigData,
|
|
10
|
+
targetFeatures,
|
|
10
11
|
} from '@voxgig/sdkgen'
|
|
11
12
|
|
|
12
13
|
|
|
@@ -33,7 +34,10 @@ const Config = cmp(async function Config(props: any) {
|
|
|
33
34
|
|
|
34
35
|
const model: Model = ctx$.model
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
// Gated by the applicability tags, so this target never imports or
|
|
38
|
+
// registers a feature it has no source for. One rule, one place:
|
|
39
|
+
// helpers/applicability.
|
|
40
|
+
const feature = targetFeatures(model, target)
|
|
37
41
|
|
|
38
42
|
// The same config as an OBJECT, built by the shared helper so this target's
|
|
39
43
|
// literal and the data that replaces it above the threshold are the same
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
isConfigData,
|
|
14
14
|
isAuthActive,
|
|
15
15
|
resolveAuthPrefix,
|
|
16
|
+
targetFeatures,
|
|
16
17
|
} from '@voxgig/sdkgen'
|
|
17
18
|
|
|
18
19
|
|
|
@@ -38,7 +39,10 @@ const Config = cmp(async function Config(props: any) {
|
|
|
38
39
|
const model: Model = ctx$.model
|
|
39
40
|
|
|
40
41
|
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
41
|
-
|
|
42
|
+
// Gated by the applicability tags, so this target never imports or
|
|
43
|
+
// registers a feature it has no source for. One rule, one place:
|
|
44
|
+
// helpers/applicability.
|
|
45
|
+
const feature = targetFeatures(model, target)
|
|
42
46
|
|
|
43
47
|
const ff = Path.normalize(__dirname + '/../../../src/cmp/dart/fragment/')
|
|
44
48
|
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
isAuthActive,
|
|
11
11
|
isConfigData,
|
|
12
12
|
resolveAuthPrefix,
|
|
13
|
+
targetFeatures,
|
|
13
14
|
} from '@voxgig/sdkgen'
|
|
14
15
|
|
|
15
16
|
|
|
@@ -35,7 +36,10 @@ const Config = cmp(async function Config(props: any) {
|
|
|
35
36
|
const Name = model.const.Name
|
|
36
37
|
|
|
37
38
|
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
38
|
-
|
|
39
|
+
// Gated by the applicability tags, so this target never imports or
|
|
40
|
+
// registers a feature it has no source for. One rule, one place:
|
|
41
|
+
// helpers/applicability.
|
|
42
|
+
const feature = targetFeatures(model, target)
|
|
39
43
|
|
|
40
44
|
const headers = getModelPath(model, `main.${KIT}.config.headers`) || {}
|
|
41
45
|
|
|
@@ -4,6 +4,7 @@ import * as Path from 'node:path'
|
|
|
4
4
|
import {
|
|
5
5
|
cmp, each,
|
|
6
6
|
File, Folder, Content, Copy, Fragment,
|
|
7
|
+
targetFeatures,
|
|
7
8
|
} from '@voxgig/sdkgen'
|
|
8
9
|
|
|
9
10
|
|
|
@@ -38,7 +39,10 @@ const Main = cmp(async function Main(props: any) {
|
|
|
38
39
|
|
|
39
40
|
const Name = model.const.Name
|
|
40
41
|
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
41
|
-
|
|
42
|
+
// Gated by the applicability tags, so this target never imports or
|
|
43
|
+
// registers a feature it has no source for. One rule, one place:
|
|
44
|
+
// helpers/applicability.
|
|
45
|
+
const feature = targetFeatures(model, target)
|
|
42
46
|
|
|
43
47
|
const ff = Path.normalize(__dirname + '/../../../src/cmp/elixir/fragment/')
|
|
44
48
|
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
isConfigData,
|
|
17
17
|
resolveAuthPrefix,
|
|
18
18
|
serverVariables,
|
|
19
|
+
targetFeatures,
|
|
19
20
|
} from '@voxgig/sdkgen'
|
|
20
21
|
|
|
21
22
|
|
|
@@ -40,7 +41,10 @@ const Config = cmp(async function Config(props: any) {
|
|
|
40
41
|
const model: Model = ctx$.model
|
|
41
42
|
|
|
42
43
|
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
43
|
-
|
|
44
|
+
// Gated by the applicability tags, so this target never imports or
|
|
45
|
+
// registers a feature it has no source for. One rule, one place:
|
|
46
|
+
// helpers/applicability.
|
|
47
|
+
const feature = targetFeatures(model, target)
|
|
44
48
|
|
|
45
49
|
const headers = getModelPath(model, `main.${KIT}.config.headers`) || {}
|
|
46
50
|
|
|
@@ -4,7 +4,8 @@ import * as Path from 'node:path'
|
|
|
4
4
|
import {
|
|
5
5
|
cmp, each, names, cmap,
|
|
6
6
|
List, File, Content, Copy, Folder, Fragment, Line, FeatureHook,
|
|
7
|
-
entityClassName, entityCollection, goModule, goPackageIdent
|
|
7
|
+
entityClassName, entityCollection, goModule, goPackageIdent,
|
|
8
|
+
targetFeatures,
|
|
8
9
|
} from '@voxgig/sdkgen'
|
|
9
10
|
|
|
10
11
|
|
|
@@ -33,7 +34,10 @@ const Main = cmp(async function Main(props: any) {
|
|
|
33
34
|
const { model } = props.ctx$
|
|
34
35
|
|
|
35
36
|
const entity: ModelEntity = getModelPath(model, `main.${KIT}.entity`)
|
|
36
|
-
|
|
37
|
+
// Gated by the applicability tags, so this target never imports or
|
|
38
|
+
// registers a feature it has no source for. One rule, one place:
|
|
39
|
+
// helpers/applicability.
|
|
40
|
+
const feature = targetFeatures(model, target)
|
|
37
41
|
|
|
38
42
|
// Go module path == the repo path on GitHub (org from model.origin),
|
|
39
43
|
// e.g. github.com/voxgig-sdk/<slug>-sdk. Used in go.mod and every import.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { cmp, Content, isAuthActive, envName, opRequestShape, entityIdField, entityOps, goModule } from '@voxgig/sdkgen'
|
|
2
|
+
import { cmp, Content, isAuthActive, envName, opRequestShape, entityIdField, entityOps, goModule , serverVariables} from '@voxgig/sdkgen'
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
KIT,
|
|
@@ -25,9 +25,22 @@ const ReadmeQuick = cmp(function ReadmeQuick(props: any) {
|
|
|
25
25
|
const exampleEntity = Object.values(entity).find((e: any) => e.active !== false) as any
|
|
26
26
|
|
|
27
27
|
const authActive = isAuthActive(model)
|
|
28
|
+
|
|
29
|
+
// Server variables (a templated server URL) are REQUIRED at construction
|
|
30
|
+
// - the SDK refuses rather than request a URL with a literal
|
|
31
|
+
// {account_id} in it - so a quickstart that omits them is a quickstart
|
|
32
|
+
// that fails on its first line.
|
|
33
|
+
const svars = serverVariables(model)
|
|
34
|
+
const goServerField = 0 === svars.length ? '' :
|
|
35
|
+
`\n "server": map[string]any{` +
|
|
36
|
+
svars.map((v: any) => `\n "${v.name}": "<${v.name}>",`).join('') +
|
|
37
|
+
`\n },`
|
|
38
|
+
|
|
28
39
|
const ctor = authActive
|
|
29
|
-
? `sdk.New${model.const.Name}SDK(map[string]any{\n "apikey": os.Getenv("${envName(model)}_APIKEY")
|
|
30
|
-
:
|
|
40
|
+
? `sdk.New${model.const.Name}SDK(map[string]any{\n "apikey": os.Getenv("${envName(model)}_APIKEY"),${goServerField}\n })`
|
|
41
|
+
: ('' === goServerField
|
|
42
|
+
? `sdk.New()`
|
|
43
|
+
: `sdk.New${model.const.Name}SDK(map[string]any{${goServerField}\n })`)
|
|
31
44
|
|
|
32
45
|
// Build the body of main() from the operations the example entity
|
|
33
46
|
// supports. Each op names a fresh value var, so `:=` always declares a
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { cmp, Content, isAuthActive, envName, entityIdField, entityOps, opRequestShape, goModule } from '@voxgig/sdkgen'
|
|
2
|
+
import { cmp, Content, isAuthActive, envName, entityIdField, entityOps, opRequestShape, goModule , serverVariables} from '@voxgig/sdkgen'
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
KIT,
|
|
@@ -20,9 +20,22 @@ const ReadmeTopQuick = cmp(function ReadmeTopQuick(props: any) {
|
|
|
20
20
|
const exampleEntity = Object.values(entity).find((e: any) => e.active !== false) as any
|
|
21
21
|
|
|
22
22
|
const authActive = isAuthActive(model)
|
|
23
|
+
|
|
24
|
+
// Server variables (a templated server URL) are REQUIRED at construction
|
|
25
|
+
// - the SDK refuses rather than request a URL with a literal
|
|
26
|
+
// {account_id} in it - so a quickstart that omits them is a quickstart
|
|
27
|
+
// that fails on its first line.
|
|
28
|
+
const svars = serverVariables(model)
|
|
29
|
+
const goServerField = 0 === svars.length ? '' :
|
|
30
|
+
`\n "server": map[string]any{` +
|
|
31
|
+
svars.map((v: any) => `\n "${v.name}": "<${v.name}>",`).join('') +
|
|
32
|
+
`\n },`
|
|
33
|
+
|
|
23
34
|
const ctor = authActive
|
|
24
|
-
? `sdk.New${model.const.Name}SDK(map[string]any{\n "apikey": os.Getenv("${envName(model)}_APIKEY")
|
|
25
|
-
:
|
|
35
|
+
? `sdk.New${model.const.Name}SDK(map[string]any{\n "apikey": os.Getenv("${envName(model)}_APIKEY"),${goServerField}\n})`
|
|
36
|
+
: ('' === goServerField
|
|
37
|
+
? `sdk.New()`
|
|
38
|
+
: `sdk.New${model.const.Name}SDK(map[string]any{${goServerField}\n})`)
|
|
26
39
|
|
|
27
40
|
Content(`\`\`\`go
|
|
28
41
|
import sdk "${gomodule}"
|
|
@@ -11,7 +11,9 @@ import {
|
|
|
11
11
|
File,
|
|
12
12
|
cmp,
|
|
13
13
|
snakify,
|
|
14
|
-
isAuthActive,
|
|
14
|
+
isAuthActive,
|
|
15
|
+
serverVarEnv,
|
|
16
|
+
serverVariables, envName, envToken, liveStrict
|
|
15
17
|
} from '@voxgig/sdkgen'
|
|
16
18
|
|
|
17
19
|
|
|
@@ -73,12 +75,26 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
73
75
|
|
|
74
76
|
const authActive = isAuthActive(model)
|
|
75
77
|
const apikeyEnvEntry = authActive
|
|
76
|
-
? `\n\t\t"${PROJECTNAME}_APIKEY": "
|
|
78
|
+
? `\n\t\t"${PROJECTNAME}_APIKEY": "",`
|
|
77
79
|
: ''
|
|
78
80
|
const apikeyLiveField = authActive
|
|
79
81
|
? `\n\t\t\t"apikey": env["${PROJECTNAME}_APIKEY"],`
|
|
80
82
|
: ''
|
|
81
83
|
|
|
84
|
+
// A templated server URL (OpenAPI server variables) makes a LIVE client
|
|
85
|
+
// impossible to construct without values: makeOptions refuses rather than
|
|
86
|
+
// request a URL with a literal `{account_id}` in it. Taken from the
|
|
87
|
+
// environment, the same way the apikey is.
|
|
88
|
+
const svars = serverVariables(model)
|
|
89
|
+
const serverEnvEntry = svars
|
|
90
|
+
.map((v: any) => `\n\t\t"${serverVarEnv(PROJECTNAME, v.name)}": ${JSON.stringify(v.dflt)},`).join('')
|
|
91
|
+
const serverLiveField = 0 === svars.length ? '' :
|
|
92
|
+
`\n\t\t"server": map[string]any{` +
|
|
93
|
+
svars.map((v: any) =>
|
|
94
|
+
`\n\t\t\t"${v.name}": env["${serverVarEnv(PROJECTNAME, v.name)}"],`).join('') +
|
|
95
|
+
`\n\t\t},`
|
|
96
|
+
|
|
97
|
+
|
|
82
98
|
const opnames = Object.keys(entity.op || {})
|
|
83
99
|
const hasLoad = opnames.includes('load')
|
|
84
100
|
const hasList = opnames.includes('list')
|
|
@@ -559,13 +575,21 @@ func ${entity.name}DirectSetup(mockres any) *${entity.name}DirectSetupResult {
|
|
|
559
575
|
|
|
560
576
|
env := envOverride(map[string]any{
|
|
561
577
|
"${entidEnvVar}": map[string]any{},
|
|
562
|
-
"${PROJECTNAME}_TEST_LIVE": "FALSE",${apikeyEnvEntry}
|
|
578
|
+
"${PROJECTNAME}_TEST_LIVE": "FALSE",${apikeyEnvEntry}${serverEnvEntry}
|
|
563
579
|
})
|
|
564
580
|
|
|
565
581
|
live := env["${PROJECTNAME}_TEST_LIVE"] == "TRUE"
|
|
566
582
|
|
|
567
583
|
if live {
|
|
568
|
-
|
|
584
|
+
// sdk-test-control.json's test.client.options seeds the live
|
|
585
|
+
// client; the generated fields below overwrite anything they name.
|
|
586
|
+
mergedOpts := map[string]any{}
|
|
587
|
+
for k, v := range liveClientOptions() {
|
|
588
|
+
mergedOpts[k] = v
|
|
589
|
+
}
|
|
590
|
+
for k, v := range map[string]any{${apikeyLiveField}${serverLiveField}
|
|
591
|
+
} {
|
|
592
|
+
mergedOpts[k] = v
|
|
569
593
|
}
|
|
570
594
|
client := sdk.New${model.const.Name}SDK(mergedOpts)
|
|
571
595
|
|
|
@@ -24,6 +24,8 @@ import {
|
|
|
24
24
|
buildIdNames,
|
|
25
25
|
getMatchEntries,
|
|
26
26
|
isAuthActive,
|
|
27
|
+
serverVarEnv,
|
|
28
|
+
serverVariables,
|
|
27
29
|
entityDataIdField, envName, envToken
|
|
28
30
|
} from '@voxgig/sdkgen'
|
|
29
31
|
|
|
@@ -71,12 +73,26 @@ const TestEntity = cmp(function TestEntity(props: any) {
|
|
|
71
73
|
|
|
72
74
|
const authActive = isAuthActive(model)
|
|
73
75
|
const apikeyEnvEntry = authActive
|
|
74
|
-
? `\n\t\t"${PROJUPPER}_APIKEY": "
|
|
76
|
+
? `\n\t\t"${PROJUPPER}_APIKEY": "",`
|
|
75
77
|
: ''
|
|
76
78
|
const apikeyLiveField = authActive
|
|
77
79
|
? `\n\t\t\t\t"apikey": env["${PROJUPPER}_APIKEY"],`
|
|
78
80
|
: ''
|
|
79
81
|
|
|
82
|
+
|
|
83
|
+
// A templated server URL (OpenAPI server variables) makes a LIVE client
|
|
84
|
+
// impossible to construct without values: makeOptions refuses rather than
|
|
85
|
+
// request a URL with a literal `{account_id}` in it. Taken from the
|
|
86
|
+
// environment, the same way the apikey is.
|
|
87
|
+
const svars = serverVariables(model)
|
|
88
|
+
const serverEnvEntry = svars
|
|
89
|
+
.map((v: any) => `\n\t\t"${serverVarEnv(PROJUPPER, v.name)}": ${JSON.stringify(v.dflt)},`).join('')
|
|
90
|
+
const serverLiveField = 0 === svars.length ? '' :
|
|
91
|
+
`\n\t\t\t\t"server": map[string]any{` +
|
|
92
|
+
svars.map((v: any) =>
|
|
93
|
+
`\n\t\t\t\t\t"${v.name}": env["${serverVarEnv(PROJUPPER, v.name)}"],`).join('') +
|
|
94
|
+
`\n\t\t\t\t},`
|
|
95
|
+
|
|
80
96
|
const idnames = buildIdNames(entity, basicflow)
|
|
81
97
|
const idnamesStr = idnames.map(n => `"${n}"`).join(', ')
|
|
82
98
|
|
|
@@ -205,7 +221,7 @@ ${allSteps.length > 0 ? '\t\tclient := setup.client\n\n' : ''}`)
|
|
|
205
221
|
const preambleRef = entity.name + '_ref01'
|
|
206
222
|
const preambleVar = goVar(preambleRef)
|
|
207
223
|
Content(` // Bootstrap entity data from existing test data (no create step in flow).
|
|
208
|
-
${preambleVar}DataRaw := vs.Items(core.ToMapAny(vs.GetPath("existing.${entity.name}"
|
|
224
|
+
${preambleVar}DataRaw := vs.Items(core.ToMapAny(vs.GetPath(setup.data, "existing.${entity.name}")))
|
|
209
225
|
var ${preambleVar}Data map[string]any
|
|
210
226
|
if len(${preambleVar}DataRaw) > 0 {
|
|
211
227
|
${preambleVar}Data = core.ToMapAny(${preambleVar}DataRaw[0][1])
|
|
@@ -265,9 +281,14 @@ ${allSteps.length > 0 ? '\t\tclient := setup.client\n\n' : ''}`)
|
|
|
265
281
|
|
|
266
282
|
`)
|
|
267
283
|
|
|
268
|
-
// Generate idmap via vs.Transform
|
|
284
|
+
// Generate idmap via vs.Transform.
|
|
285
|
+
//
|
|
286
|
+
// The error return Transform gained in struct go 0.1.3 is discarded
|
|
287
|
+
// deliberately: this transforms the entity's own id names, which the
|
|
288
|
+
// generator produced, so an error would be a generator bug rather than
|
|
289
|
+
// anything the generated test can act on.
|
|
269
290
|
Content('\t// Generate idmap via transform, matching TS pattern.\n')
|
|
270
|
-
Content('\tidmap := vs.Transform(\n')
|
|
291
|
+
Content('\tidmap, _ := vs.Transform(\n')
|
|
271
292
|
Content('\t\t[]any{' + idnamesStr + '},\n')
|
|
272
293
|
Content('\t\tmap[string]any{\n')
|
|
273
294
|
Content('\t\t\t"`$PACK`": []any{"", map[string]any{\n')
|
|
@@ -287,7 +308,7 @@ ${allSteps.length > 0 ? '\t\tclient := setup.client\n\n' : ''}`)
|
|
|
287
308
|
env := envOverride(map[string]any{
|
|
288
309
|
"${PROJUPPER}_TEST_${envToken(entity.name)}_ENTID": idmap,
|
|
289
310
|
"${PROJUPPER}_TEST_LIVE": "FALSE",
|
|
290
|
-
"${PROJUPPER}_TEST_EXPLAIN": "FALSE",${apikeyEnvEntry}
|
|
311
|
+
"${PROJUPPER}_TEST_EXPLAIN": "FALSE",${apikeyEnvEntry}${serverEnvEntry}
|
|
291
312
|
})
|
|
292
313
|
|
|
293
314
|
idmapResolved := core.ToMapAny(env["${PROJUPPER}_TEST_${envToken(entity.name)}_ENTID"])
|
|
@@ -307,10 +328,22 @@ ${allSteps.length > 0 ? '\t\tclient := setup.client\n\n' : ''}`)
|
|
|
307
328
|
|
|
308
329
|
Content(`
|
|
309
330
|
if env["${PROJUPPER}_TEST_LIVE"] == "TRUE" {
|
|
331
|
+
// An empty map, not a nil one: Merge returns nil when its last entry
|
|
332
|
+
// is nil, and BasicSetup is normally called with no extras - so a
|
|
333
|
+
// bare nil silently discarded the apikey and server values below.
|
|
334
|
+
extraOpts := extra
|
|
335
|
+
if extraOpts == nil {
|
|
336
|
+
extraOpts = map[string]any{}
|
|
337
|
+
}
|
|
338
|
+
|
|
310
339
|
mergedOpts := vs.Merge([]any{
|
|
311
|
-
|
|
340
|
+
// liveClientOptions() FIRST, so the generated fields below win:
|
|
341
|
+
// sdk-test-control.json's test.client.options adds to the live
|
|
342
|
+
// client, it does not redirect it.
|
|
343
|
+
liveClientOptions(),
|
|
344
|
+
map[string]any{${apikeyLiveField}${serverLiveField}
|
|
312
345
|
},
|
|
313
|
-
|
|
346
|
+
extraOpts,
|
|
314
347
|
})
|
|
315
348
|
client = sdk.New${model.const.Name}SDK(core.ToMapAny(mergedOpts))
|
|
316
349
|
}
|
|
@@ -361,11 +394,11 @@ const generateCreate: OpGen = (ctx, step, index) => {
|
|
|
361
394
|
// Load data from test data file
|
|
362
395
|
if (hasDatvar) {
|
|
363
396
|
Content(` ${datavar} = core.ToMapAny(vs.GetProp(
|
|
364
|
-
vs.GetPath([]any{"new", "${entity.name}"}
|
|
397
|
+
vs.GetPath(setup.data, []any{"new", "${entity.name}"}), "${ref}"))
|
|
365
398
|
`)
|
|
366
399
|
} else {
|
|
367
400
|
Content(` ${datavar} := core.ToMapAny(vs.GetProp(
|
|
368
|
-
vs.GetPath([]any{"new", "${entity.name}"}
|
|
401
|
+
vs.GetPath(setup.data, []any{"new", "${entity.name}"}), "${ref}"))
|
|
369
402
|
`)
|
|
370
403
|
}
|
|
371
404
|
|
|
@@ -606,7 +639,7 @@ const generateLoad: OpGen = (ctx, step, index) => {
|
|
|
606
639
|
`)
|
|
607
640
|
}
|
|
608
641
|
if (!hasSrcData && hasEntId) {
|
|
609
|
-
Content(` ${srcdatavar}Raw := vs.Items(core.ToMapAny(vs.GetPath("existing.${entity.name}"
|
|
642
|
+
Content(` ${srcdatavar}Raw := vs.Items(core.ToMapAny(vs.GetPath(setup.data, "existing.${entity.name}")))
|
|
610
643
|
var ${srcdatavar} map[string]any
|
|
611
644
|
if len(${srcdatavar}Raw) > 0 {
|
|
612
645
|
${srcdatavar} = core.ToMapAny(${srcdatavar}Raw[0][1])
|