@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
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// Which features a target can actually take.
|
|
2
|
+
//
|
|
3
|
+
// THE ONE PLACE THIS RULE LIVES. `Feature` (what source is copied), the
|
|
4
|
+
// per-language `Config_<lang>` and `Main_<lang>` components (what the
|
|
5
|
+
// generated registry, imports and metadata contain) and `configDefinition`
|
|
6
|
+
// (the embedded config) must all reach the same answer for one
|
|
7
|
+
// (feature, target) pair. They previously each read the raw feature map,
|
|
8
|
+
// which is how a feature with no source for a target still reached that
|
|
9
|
+
// target's imports.
|
|
10
|
+
//
|
|
11
|
+
// The shape is `docs/design/feature-tags.md`: a feature declares what it
|
|
12
|
+
// NEEDS, a target declares what it PROVIDES, and the feature applies when
|
|
13
|
+
// `needs` is a subset of `provides`. Both default to empty, so a feature
|
|
14
|
+
// that needs nothing applies everywhere — every feature that existed
|
|
15
|
+
// before this gate keeps its behaviour with no model edit, which is what
|
|
16
|
+
// makes the change additive.
|
|
17
|
+
//
|
|
18
|
+
// A named target list was the cheaper design and fails on time: it has to
|
|
19
|
+
// be edited for targets the feature's author has never heard of, so a
|
|
20
|
+
// published package starves every target added after its release. A tag is
|
|
21
|
+
// a claim about the feature that stays true as the target set grows.
|
|
22
|
+
|
|
23
|
+
import { KIT, getModelPath } from '@voxgig/apidef'
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
// Tags are a MAP keyed by tag name, `{ sekreto: true }` — see the schema
|
|
27
|
+
// note on `needs`. A map because aontu unifies maps by key, so a package
|
|
28
|
+
// can add one tag without restating the others; and because a defaulted
|
|
29
|
+
// list disjunction in this position hangs the unifier on a real project's
|
|
30
|
+
// model. A tag counts only when its value is true, so a tag can be turned
|
|
31
|
+
// off by overriding it rather than by deleting the key.
|
|
32
|
+
//
|
|
33
|
+
// A list is still accepted, for a hand-written model that used the shape
|
|
34
|
+
// docs/design/feature-tags.md first proposed.
|
|
35
|
+
function tags(val: any): string[] {
|
|
36
|
+
if (Array.isArray(val)) {
|
|
37
|
+
return val.filter((t: any) => 'string' === typeof t)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (null == val || 'object' !== typeof val) {
|
|
41
|
+
return []
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return Object.keys(val).filter((name: string) => true === val[name])
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
// Does this feature apply to this target?
|
|
49
|
+
function featureApplies(feature: any, target: any): boolean {
|
|
50
|
+
const needs = tags(feature && feature.needs)
|
|
51
|
+
|
|
52
|
+
// The common case, and the reason this is additive: no needs, applies
|
|
53
|
+
// anywhere. Checked first so a target with no `provides` is unaffected.
|
|
54
|
+
if (0 === needs.length) {
|
|
55
|
+
return true
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const provides = tags(target && target.provides)
|
|
59
|
+
|
|
60
|
+
return needs.every((need: string) => provides.includes(need))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
// The features that apply to `target`, in the same map shape
|
|
65
|
+
// `getModelPath(model, 'main.<kit>.feature')` returns — already
|
|
66
|
+
// active-filtered by getModelPath, then gated by the tags.
|
|
67
|
+
//
|
|
68
|
+
// `target` may be the target object or its name; components hold the
|
|
69
|
+
// object, `configDefinition` is only given the name.
|
|
70
|
+
function targetFeatures(model: any, target: any): Record<string, any> {
|
|
71
|
+
const feature = getModelPath(model, `main.${KIT}.feature`, { required: false }) || {}
|
|
72
|
+
|
|
73
|
+
const t = 'string' === typeof target ?
|
|
74
|
+
(getModelPath(model, `main.${KIT}.target`, { required: false }) || {})[target] :
|
|
75
|
+
target
|
|
76
|
+
|
|
77
|
+
// A name that names no target gates nothing: a caller that cannot say
|
|
78
|
+
// which target it is generating for must not silently lose features.
|
|
79
|
+
if (null == t) {
|
|
80
|
+
return feature
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Keyed off the map, not off `f.name`: the key is what every consumer
|
|
84
|
+
// indexes by, and rebuilding from a field would drop an entry whose
|
|
85
|
+
// model never set one. Order is not preserved on purpose — consumers
|
|
86
|
+
// re-sort with `each`, which is what keeps output byte-stable.
|
|
87
|
+
const applies: Record<string, any> = {}
|
|
88
|
+
for (const [name, f] of Object.entries(feature as Record<string, any>)) {
|
|
89
|
+
if (featureApplies(f, t)) {
|
|
90
|
+
applies[name] = f
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return applies
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
// THE CLOSED VOCABULARY. The schema comment says applicability tags are a
|
|
99
|
+
// closed set; without this, `provides: &: boolean` accepts any key, so a
|
|
100
|
+
// typo (`sekrreto`) compiles cleanly and silently makes the feature apply
|
|
101
|
+
// NOWHERE — the worst failure shape, because the feature simply vanishes
|
|
102
|
+
// with no diagnostic.
|
|
103
|
+
//
|
|
104
|
+
// Extended by adding a tag here AND documenting it in model/sdkgen.aon.
|
|
105
|
+
const TAGS = [
|
|
106
|
+
// A vendored sekreto port lives in this target's feature container.
|
|
107
|
+
'sekreto',
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
// The tags named by `needs`/`provides` that are not in the vocabulary.
|
|
112
|
+
function unknownTags(val: any): string[] {
|
|
113
|
+
return tags(val).filter((t: string) => !TAGS.includes(t))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
export {
|
|
118
|
+
featureApplies,
|
|
119
|
+
targetFeatures,
|
|
120
|
+
tags as featureTags,
|
|
121
|
+
unknownTags,
|
|
122
|
+
TAGS,
|
|
123
|
+
}
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
// need extra fields like `dep.replace` (go module replace directives) or
|
|
12
12
|
// `dep.kind` (prod/dev/peer).
|
|
13
13
|
|
|
14
|
+
import { targetFeatures } from './applicability'
|
|
15
|
+
|
|
14
16
|
import { each } from 'jostraca'
|
|
15
17
|
import { KIT, getModelPath } from '@voxgig/apidef'
|
|
16
18
|
|
|
@@ -30,7 +32,9 @@ function collectDeps(
|
|
|
30
32
|
log?: any,
|
|
31
33
|
): DepEntry[] {
|
|
32
34
|
const out: DepEntry[] = []
|
|
33
|
-
|
|
35
|
+
// Gated: a feature that does not apply to this target must not flow a
|
|
36
|
+
// dependency into its generated manifest.
|
|
37
|
+
const feature = targetFeatures(model, targetName)
|
|
34
38
|
|
|
35
39
|
// Deduplicate by package name. Two features can require the same package
|
|
36
40
|
// (or a feature and the target itself can), and every Package_<lang>.ts
|
|
@@ -88,6 +88,24 @@ function serverVariables(model: any): ServerVar[] {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
|
|
91
|
+
// The environment variable a generated LIVE test reads one server variable
|
|
92
|
+
// from: `<PROJ>_SERVER_<NAME>`, e.g. ELEMENTDEMO_SERVER_ACCOUNT_ID.
|
|
93
|
+
//
|
|
94
|
+
// A live client CANNOT BE CONSTRUCTED without every required server
|
|
95
|
+
// variable — makeOptions raises rather than issue requests to a URL with a
|
|
96
|
+
// literal `{account_id}` in it — so an SDK whose spec templates its server
|
|
97
|
+
// URL had no runnable live suite at all until the generated tests could be
|
|
98
|
+
// told the values. The apikey has had `<PROJ>_APIKEY` since the beginning;
|
|
99
|
+
// this is the same idea for the other half of "where do I point".
|
|
100
|
+
//
|
|
101
|
+
// One variable per NAME rather than one JSON blob: the names come from the
|
|
102
|
+
// spec, they are few, and a shell export per name is what a CI secret store
|
|
103
|
+
// and a .env file both hold naturally.
|
|
104
|
+
function serverVarEnv(projenvname: string, name: string): string {
|
|
105
|
+
return projenvname + '_SERVER_' + String(name).toUpperCase()
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
91
109
|
// Does the model's server URL contain any {name} placeholders at all?
|
|
92
110
|
function hasServerVariables(model: any): boolean {
|
|
93
111
|
const info = model?.main?.kit?.info || model?.main?.KIT?.info
|
|
@@ -100,6 +118,7 @@ function hasServerVariables(model: any): boolean {
|
|
|
100
118
|
export {
|
|
101
119
|
serverVariables,
|
|
102
120
|
hasServerVariables,
|
|
121
|
+
serverVarEnv,
|
|
103
122
|
}
|
|
104
123
|
|
|
105
124
|
export type { ServerVar }
|
package/src/sdkgen.ts
CHANGED
|
@@ -22,6 +22,7 @@ import { SdkGenError, requirePath, isAuthActive, resolveAuthPrefix, isHttpBasicA
|
|
|
22
22
|
configReprSetting, configDefinition, clean, rawStringLiteral } from './utility'
|
|
23
23
|
|
|
24
24
|
import { Main } from './cmp/Main'
|
|
25
|
+
import { featureApplies, targetFeatures, featureTags, unknownTags, TAGS } from './helpers/applicability'
|
|
25
26
|
import { ExternalTarget } from './cmp/ExternalTarget'
|
|
26
27
|
import { Docs, DocsItem } from './cmp/Docs'
|
|
27
28
|
import { ExternalDocs } from './cmp/ExternalDocs'
|
|
@@ -61,7 +62,7 @@ import type { DepEntry } from './helpers/collectDeps'
|
|
|
61
62
|
import { canonToType, canonToDtype, canonKey, canonScalarKey } from './helpers/canonType'
|
|
62
63
|
import { OP_SUFFIX, opTypeName, opParams, ownPoint, opActions, entityActions, entityPath, opRequestShape, entityIdField, entityDataIdField, entityOps, entityPrimaryOp, pickExampleEntity, entityClassName, entityTypeCollisions, warnEntityTypeCollisions, deriveEntityNames, entityCollection } from './helpers/opShape'
|
|
63
64
|
import { isReservedName, safeVarName, exampleVarName, phpEntityAccessor, entityCacheField, isRbCoreConstant, isRbSdkConstant, rbSafeTypeName, isSwiftSdkType, swiftSafeTypeName, isPhpReservedType, isPhpSdkClass, phpSafeTypeName, isTsReservedType, tsSafeTypeName, jsProp, jsOptProp, jsKey } from './helpers/naming'
|
|
64
|
-
import { serverVariables, hasServerVariables } from './helpers/serverVars'
|
|
65
|
+
import { serverVariables, hasServerVariables, serverVarEnv } from './helpers/serverVars'
|
|
65
66
|
import { primaryOpCall, idLiteral, matchArg, dataArg, litFor } from './helpers/opExample'
|
|
66
67
|
import type { ExampleLang } from './helpers/opExample'
|
|
67
68
|
import { liveStrict } from './helpers/testPolicy'
|
|
@@ -1153,6 +1154,7 @@ export {
|
|
|
1153
1154
|
tsSafeTypeName,
|
|
1154
1155
|
serverVariables,
|
|
1155
1156
|
hasServerVariables,
|
|
1157
|
+
serverVarEnv,
|
|
1156
1158
|
liveStrict,
|
|
1157
1159
|
primaryOpCall,
|
|
1158
1160
|
idLiteral,
|
|
@@ -1167,6 +1169,12 @@ export {
|
|
|
1167
1169
|
srcFeatureExcludes,
|
|
1168
1170
|
stationLibrary,
|
|
1169
1171
|
|
|
1172
|
+
featureApplies,
|
|
1173
|
+
targetFeatures,
|
|
1174
|
+
featureTags,
|
|
1175
|
+
unknownTags,
|
|
1176
|
+
TAGS,
|
|
1177
|
+
|
|
1170
1178
|
definitionPath,
|
|
1171
1179
|
definitionFolder,
|
|
1172
1180
|
definitionNames,
|
package/src/utility.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { JostracaResult, each } from 'jostraca'
|
|
|
5
5
|
|
|
6
6
|
import { KIT, getModelPath } from '@voxgig/apidef'
|
|
7
7
|
|
|
8
|
+
import { targetFeatures } from './helpers/applicability'
|
|
9
|
+
|
|
8
10
|
import { serverVariables } from './helpers/serverVars'
|
|
9
11
|
import { packageVersion } from './helpers/packageMeta'
|
|
10
12
|
|
|
@@ -312,7 +314,14 @@ function rawStringLiteral(s: string): string {
|
|
|
312
314
|
// across runs exactly like the literal it replaces.
|
|
313
315
|
function configDefinition(model: any, targetname?: string): { def: any, json: string } {
|
|
314
316
|
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
315
|
-
|
|
317
|
+
|
|
318
|
+
// Gated by the target when one is named, so the embedded config cannot
|
|
319
|
+
// advertise a feature this target has no implementation for — the exact
|
|
320
|
+
// hybrid state the applicability gate exists to prevent. With no
|
|
321
|
+
// targetname (a caller that cannot say which target it is building) the
|
|
322
|
+
// helper returns every active feature, i.e. the old behaviour.
|
|
323
|
+
const feature = targetFeatures(model, targetname)
|
|
324
|
+
|
|
316
325
|
const headers = getModelPath(model, `main.${KIT}.config.headers`) || {}
|
|
317
326
|
|
|
318
327
|
const authActive = isAuthActive(model)
|
|
@@ -1,425 +0,0 @@
|
|
|
1
|
-
// VERSION: @voxgig/struct 0.0.10
|
|
2
|
-
// This test utility runs the JSON-specified tests in build/test/test.json.
|
|
3
|
-
// (or .sdk/test/test.json if used in a @voxgig/sdkgen project)
|
|
4
|
-
|
|
5
|
-
import { readFileSync } from 'node:fs'
|
|
6
|
-
import { join } from 'node:path'
|
|
7
|
-
import { deepStrictEqual, fail, AssertionError } from 'node:assert'
|
|
8
|
-
|
|
9
|
-
const NULLMARK = '__NULL__' // Value is JSON null
|
|
10
|
-
const UNDEFMARK = '__UNDEF__' // Value is not present (thus, undefined).
|
|
11
|
-
const EXISTSMARK = '__EXISTS__' // Value exists (not undefined).
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
type Subject = (...args: any[]) => any
|
|
15
|
-
type RunSet = (testspec: any, testsubject: Function) => Promise<any>
|
|
16
|
-
type RunSetFlags = (testspec: any, flags: Record<string, boolean>, testsubject: Function)
|
|
17
|
-
=> Promise<any>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
type RunPack = {
|
|
21
|
-
spec: Record<string, any>
|
|
22
|
-
runset: RunSet
|
|
23
|
-
runsetflags: RunSetFlags
|
|
24
|
-
subject: Subject
|
|
25
|
-
client: any
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
type TestPack = {
|
|
30
|
-
name?: string
|
|
31
|
-
client: any
|
|
32
|
-
subject: Subject
|
|
33
|
-
utility: any
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
type Flags = Record<string, boolean>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
type Utility = {
|
|
40
|
-
struct: any
|
|
41
|
-
makeContext: (ctxmap: Record<string, any>, basectx?: any) => any
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
type Client = {
|
|
46
|
-
utility: () => Utility
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
async function makeRunner(testfile: string, client: Client) {
|
|
51
|
-
|
|
52
|
-
return async function runner(
|
|
53
|
-
name: string,
|
|
54
|
-
store?: any,
|
|
55
|
-
): Promise<RunPack> {
|
|
56
|
-
store = store || {}
|
|
57
|
-
|
|
58
|
-
const utility = client.utility()
|
|
59
|
-
const structUtils = utility.struct
|
|
60
|
-
|
|
61
|
-
let spec = resolveSpec(name, testfile)
|
|
62
|
-
let clients = await resolveClients(client, spec, store, structUtils)
|
|
63
|
-
let subject = resolveSubject(name, utility)
|
|
64
|
-
|
|
65
|
-
let runsetflags: RunSetFlags = async (
|
|
66
|
-
testspec: any,
|
|
67
|
-
flags: Flags,
|
|
68
|
-
testsubject: Function
|
|
69
|
-
) => {
|
|
70
|
-
subject = testsubject || subject
|
|
71
|
-
flags = resolveFlags(flags)
|
|
72
|
-
const testspecmap = fixJSON(testspec, flags)
|
|
73
|
-
|
|
74
|
-
const testset: any[] = testspecmap.set
|
|
75
|
-
for (let entry of testset) {
|
|
76
|
-
try {
|
|
77
|
-
entry = resolveEntry(entry, flags)
|
|
78
|
-
|
|
79
|
-
let testpack = resolveTestPack(name, entry, subject, client, clients)
|
|
80
|
-
let args = resolveArgs(entry, testpack, utility, structUtils)
|
|
81
|
-
|
|
82
|
-
let res = await testpack.subject(...args)
|
|
83
|
-
res = fixJSON(res, flags)
|
|
84
|
-
entry.res = res
|
|
85
|
-
|
|
86
|
-
checkResult(entry, args, res, structUtils)
|
|
87
|
-
}
|
|
88
|
-
catch (err: any) {
|
|
89
|
-
if (err instanceof AssertionError) {
|
|
90
|
-
throw err
|
|
91
|
-
}
|
|
92
|
-
handleError(entry, err, structUtils)
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
let runset: RunSet = async (
|
|
98
|
-
testspec: any,
|
|
99
|
-
testsubject: Function
|
|
100
|
-
) => runsetflags(testspec, {}, testsubject)
|
|
101
|
-
|
|
102
|
-
const runpack: RunPack = {
|
|
103
|
-
spec,
|
|
104
|
-
runset,
|
|
105
|
-
runsetflags,
|
|
106
|
-
subject,
|
|
107
|
-
client,
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return runpack
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function resolveSpec(name: string, testfile: string): Record<string, any> {
|
|
115
|
-
const alltests =
|
|
116
|
-
JSON.parse(readFileSync(join(__dirname, testfile), 'utf8'))
|
|
117
|
-
|
|
118
|
-
let spec = alltests.primary?.[name] || alltests[name] || alltests
|
|
119
|
-
return spec
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
async function resolveClients(
|
|
124
|
-
client: any,
|
|
125
|
-
spec: Record<string, any>,
|
|
126
|
-
store: any,
|
|
127
|
-
structUtils: Record<string, any>
|
|
128
|
-
):
|
|
129
|
-
Promise<Record<string, any>> {
|
|
130
|
-
|
|
131
|
-
const clients: Record<string, any> = {}
|
|
132
|
-
if (spec.DEF && spec.DEF.client) {
|
|
133
|
-
for (let cn in spec.DEF.client) {
|
|
134
|
-
const cdef = spec.DEF.client[cn]
|
|
135
|
-
const copts = cdef.test.options || {}
|
|
136
|
-
if ('object' === typeof store && structUtils?.inject) {
|
|
137
|
-
structUtils.inject(copts, store)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
clients[cn] = await client.tester(copts)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return clients
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
function resolveSubject(name: string, container: any) {
|
|
148
|
-
const subject = container[name] || container.struct[name]
|
|
149
|
-
return subject
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
function resolveFlags(flags?: Flags): Flags {
|
|
154
|
-
if (null == flags) {
|
|
155
|
-
flags = {}
|
|
156
|
-
}
|
|
157
|
-
flags.null = null == flags.null ? true : !!flags.null
|
|
158
|
-
return flags
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
function resolveEntry(entry: any, flags: Flags): any {
|
|
163
|
-
entry.out = null == entry.out && flags.null ? NULLMARK : entry.out
|
|
164
|
-
return entry
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
function checkResult(entry: any, args: any[], res: any, structUtils: Record<string, any>) {
|
|
169
|
-
let matched = false
|
|
170
|
-
|
|
171
|
-
if (entry.err) {
|
|
172
|
-
return fail('Expected error did not occur: ' + entry.err +
|
|
173
|
-
'\n\nENTRY: ' + safeStringify(entry))
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (entry.match) {
|
|
177
|
-
const result = { in: entry.in, args, out: entry.res, ctx: entry.ctx }
|
|
178
|
-
match(
|
|
179
|
-
entry.match,
|
|
180
|
-
result,
|
|
181
|
-
structUtils
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
matched = true
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const out = entry.out
|
|
188
|
-
|
|
189
|
-
if (out === res) {
|
|
190
|
-
return
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// NOTE: allow match with no out.
|
|
194
|
-
if (matched && (NULLMARK === out || null == out)) {
|
|
195
|
-
return
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
deepStrictEqual(null != res ? JSON.parse(safeStringify(res)) : res, entry.out)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
// Handle errors from test execution
|
|
203
|
-
function handleError(entry: any, err: any, structUtils: Record<string, any>) {
|
|
204
|
-
entry.thrown = err
|
|
205
|
-
|
|
206
|
-
const entry_err = entry.err
|
|
207
|
-
|
|
208
|
-
if (null != entry_err) {
|
|
209
|
-
if (true === entry_err || matchval(entry_err, err.message, structUtils)) {
|
|
210
|
-
if (entry.match) {
|
|
211
|
-
match(
|
|
212
|
-
entry.match,
|
|
213
|
-
{ in: entry.in, out: entry.res, ctx: entry.ctx, err: fixJSON(err, { null: true }) },
|
|
214
|
-
structUtils
|
|
215
|
-
)
|
|
216
|
-
}
|
|
217
|
-
return
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
fail('ERROR MATCH: [' + structUtils.stringify(entry_err) +
|
|
221
|
-
'] <=> [' + err.message + ']')
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Unexpected error (test didn't specify an error expectation)
|
|
225
|
-
else if (err instanceof AssertionError) {
|
|
226
|
-
fail(err.message + '\n\nENTRY: ' + safeStringify(entry))
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
fail(err.stack + '\n\nENTRY: ' + safeStringify(entry))
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
function resolveArgs(
|
|
235
|
-
entry: any,
|
|
236
|
-
testpack: TestPack,
|
|
237
|
-
utility: Utility,
|
|
238
|
-
structUtils: Record<string, any>
|
|
239
|
-
): any[] {
|
|
240
|
-
let args: any[] = []
|
|
241
|
-
|
|
242
|
-
if (entry.ctx) {
|
|
243
|
-
args = [entry.ctx]
|
|
244
|
-
}
|
|
245
|
-
else if (entry.args) {
|
|
246
|
-
args = entry.args
|
|
247
|
-
}
|
|
248
|
-
else {
|
|
249
|
-
args = [structUtils.clone(entry.in)]
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if (entry.ctx || entry.args) {
|
|
253
|
-
let first = args[0]
|
|
254
|
-
if (structUtils.ismap(first)) {
|
|
255
|
-
first = structUtils.clone(first)
|
|
256
|
-
first = utility.makeContext(first)
|
|
257
|
-
args[0] = first
|
|
258
|
-
entry.ctx = first
|
|
259
|
-
|
|
260
|
-
first.client = testpack.client
|
|
261
|
-
first.utility = testpack.utility
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return args
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
function resolveTestPack(
|
|
270
|
-
name: string,
|
|
271
|
-
entry: any,
|
|
272
|
-
subject: Subject,
|
|
273
|
-
client: any,
|
|
274
|
-
clients: Record<string, any>
|
|
275
|
-
) {
|
|
276
|
-
const testpack: TestPack = {
|
|
277
|
-
name,
|
|
278
|
-
client,
|
|
279
|
-
subject,
|
|
280
|
-
utility: client.utility(),
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if (entry.client) {
|
|
284
|
-
testpack.client = clients[entry.client]
|
|
285
|
-
testpack.utility = testpack.client.utility()
|
|
286
|
-
testpack.subject = resolveSubject(name, testpack.utility)
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return testpack
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
function match(
|
|
294
|
-
check: any,
|
|
295
|
-
basex: any,
|
|
296
|
-
structUtils: Record<string, any>
|
|
297
|
-
) {
|
|
298
|
-
const cbase = structUtils.clone(basex)
|
|
299
|
-
|
|
300
|
-
structUtils.walk(check, (_key: any, val: any, _parent: any, path: any) => {
|
|
301
|
-
if (!structUtils.isnode(val)) {
|
|
302
|
-
let baseval = structUtils.getpath(cbase, path)
|
|
303
|
-
|
|
304
|
-
if (baseval === val) {
|
|
305
|
-
return val
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Explicit undefined expected
|
|
309
|
-
if (UNDEFMARK === val && undefined === baseval) {
|
|
310
|
-
return val
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// Explicit defined expected
|
|
314
|
-
if (EXISTSMARK === val && null != baseval) {
|
|
315
|
-
return val
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (!matchval(val, baseval, structUtils)) {
|
|
319
|
-
fail('MATCH: ' + path.join('.') +
|
|
320
|
-
': [' + structUtils.stringify(val) +
|
|
321
|
-
'] <=> [' + structUtils.stringify(baseval) + ']')
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
return val
|
|
326
|
-
})
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
function matchval(
|
|
331
|
-
check: any,
|
|
332
|
-
base: any,
|
|
333
|
-
structUtils: Record<string, any>
|
|
334
|
-
) {
|
|
335
|
-
let pass = check === base
|
|
336
|
-
|
|
337
|
-
if (!pass) {
|
|
338
|
-
|
|
339
|
-
if ('string' === typeof check) {
|
|
340
|
-
let basestr = structUtils.stringify(base)
|
|
341
|
-
|
|
342
|
-
let rem = check.match(/^\/(.+)\/$/)
|
|
343
|
-
if (rem) {
|
|
344
|
-
pass = new RegExp(rem[1]).test(basestr)
|
|
345
|
-
}
|
|
346
|
-
else {
|
|
347
|
-
pass = basestr.toLowerCase().includes(structUtils.stringify(check).toLowerCase())
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
else if ('function' === typeof check) {
|
|
351
|
-
pass = true
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
return pass
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
function safeStringify(val: any): string {
|
|
360
|
-
const seen = new WeakSet()
|
|
361
|
-
return JSON.stringify(val, (_k, v) => {
|
|
362
|
-
if ('object' === typeof v && null !== v) {
|
|
363
|
-
if (seen.has(v)) return '[Circular]'
|
|
364
|
-
seen.add(v)
|
|
365
|
-
}
|
|
366
|
-
if (v instanceof Error) {
|
|
367
|
-
return { name: v.name, message: v.message }
|
|
368
|
-
}
|
|
369
|
-
return v
|
|
370
|
-
}, 2)
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
function fixJSON(val: any, flags?: Flags): any {
|
|
375
|
-
if (null == val) {
|
|
376
|
-
return flags?.null ? NULLMARK : val
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
const seen = new WeakSet()
|
|
380
|
-
const replacer = (_k: string, v: any) => {
|
|
381
|
-
if (null == v && flags?.null) {
|
|
382
|
-
return NULLMARK
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (v instanceof Error) {
|
|
386
|
-
return {
|
|
387
|
-
...v,
|
|
388
|
-
name: v.name,
|
|
389
|
-
message: v.message,
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
if ('object' === typeof v && null !== v) {
|
|
394
|
-
if (seen.has(v)) return '[Circular]'
|
|
395
|
-
seen.add(v)
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
return v
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
return JSON.parse(JSON.stringify(val, replacer))
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
function nullModifier(
|
|
406
|
-
val: any,
|
|
407
|
-
key: any,
|
|
408
|
-
parent: any
|
|
409
|
-
) {
|
|
410
|
-
if ("__NULL__" === val) {
|
|
411
|
-
parent[key] = null
|
|
412
|
-
}
|
|
413
|
-
else if ('string' === typeof val) {
|
|
414
|
-
parent[key] = val.replaceAll('__NULL__', 'null')
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
export {
|
|
420
|
-
NULLMARK,
|
|
421
|
-
EXISTSMARK,
|
|
422
|
-
nullModifier,
|
|
423
|
-
makeRunner,
|
|
424
|
-
}
|
|
425
|
-
|