@voxgig/sdkgen 3.5.0 → 3.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/cmp/ExternalTarget.js +1 -1
- package/dist/cmp/ExternalTarget.js.map +1 -1
- package/dist/helpers/naming.d.ts +4 -1
- package/dist/helpers/naming.js +119 -5
- package/dist/helpers/naming.js.map +1 -1
- package/dist/helpers/opShape.js +72 -0
- package/dist/helpers/opShape.js.map +1 -1
- package/dist/helpers/packageMeta.d.ts +2 -1
- package/dist/helpers/packageMeta.js +57 -20
- package/dist/helpers/packageMeta.js.map +1 -1
- package/dist/sdkgen.d.ts +3 -3
- package/dist/sdkgen.js +61 -18
- package/dist/sdkgen.js.map +1 -1
- package/dist/testkit.d.ts +39 -0
- package/dist/testkit.js +663 -0
- package/dist/testkit.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +32 -8
- package/project/.sdk/src/cmp/c/Test_c.ts +5 -7
- package/project/.sdk/src/cmp/clojure/Test_clojure.ts +3 -7
- package/project/.sdk/src/cmp/cpp/Test_cpp.ts +4 -7
- package/project/.sdk/src/cmp/csharp/Package_csharp.ts +1 -1
- package/project/.sdk/src/cmp/csharp/Test_csharp.ts +5 -7
- package/project/.sdk/src/cmp/dart/Test_dart.ts +3 -4
- package/project/.sdk/src/cmp/elixir/Package_elixir.ts +1 -1
- package/project/.sdk/src/cmp/elixir/Test_elixir.ts +5 -6
- package/project/.sdk/src/cmp/go/EntityTypes_go.ts +1 -1
- package/project/.sdk/src/cmp/go/Entity_go.ts +1 -1
- package/project/.sdk/src/cmp/go/Gitignore_go.ts +6 -0
- package/project/.sdk/src/cmp/go/Main_go.ts +2 -2
- package/project/.sdk/src/cmp/go/Package_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeExamplesTest_go.ts +59 -6
- package/project/.sdk/src/cmp/go/ReadmeExplanation_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeHowto_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeInstall_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeTopTest_go.ts +1 -1
- package/project/.sdk/src/cmp/go/Test_go.ts +6 -8
- package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +6 -2
- package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +6 -2
- package/project/.sdk/src/cmp/java/Test_java.ts +4 -7
- package/project/.sdk/src/cmp/js/Package_js.ts +1 -1
- package/project/.sdk/src/cmp/js/Test_js.ts +4 -7
- package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +4 -7
- package/project/.sdk/src/cmp/lean/Test_lean.ts +3 -3
- package/project/.sdk/src/cmp/lua/Package_lua.ts +2 -2
- package/project/.sdk/src/cmp/lua/Test_lua.ts +5 -7
- package/project/.sdk/src/cmp/ocaml/Test_ocaml.ts +3 -7
- package/project/.sdk/src/cmp/perl/Package_perl.ts +1 -1
- package/project/.sdk/src/cmp/perl/Test_perl.ts +5 -7
- package/project/.sdk/src/cmp/php/EntityTypes_php.ts +13 -2
- package/project/.sdk/src/cmp/php/Package_php.ts +2 -2
- package/project/.sdk/src/cmp/php/Test_php.ts +5 -7
- package/project/.sdk/src/cmp/py/Package_py.ts +2 -2
- package/project/.sdk/src/cmp/py/Test_py.ts +5 -7
- package/project/.sdk/src/cmp/py-data/Main_py-data.ts +14 -19
- package/project/.sdk/src/cmp/rb/Package_rb.ts +3 -3
- package/project/.sdk/src/cmp/rb/ReadmeInstall_rb.ts +1 -1
- package/project/.sdk/src/cmp/rb/Test_rb.ts +5 -7
- package/project/.sdk/src/cmp/rust/Test_rust.ts +5 -7
- package/project/.sdk/src/cmp/scala/Test_scala.ts +5 -2
- package/project/.sdk/src/cmp/seneca-provider/Gitignore_seneca-provider.ts +161 -0
- package/project/.sdk/src/cmp/seneca-provider/Main_seneca-provider.ts +20 -11
- package/project/.sdk/src/cmp/swift/Test_swift.ts +5 -7
- package/project/.sdk/src/cmp/ts/Package_ts.ts +1 -1
- package/project/.sdk/src/cmp/ts/Test_ts.ts +8 -7
- package/project/.sdk/src/cmp/zig/Test_zig.ts +3 -7
- package/project/.sdk/tm/c/utility/make_point.c +64 -3
- package/project/.sdk/tm/clojure/src/sdk/core.clj +49 -14
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +55 -3
- package/project/.sdk/tm/csharp/feature/TestFeature.cs +36 -2
- package/project/.sdk/tm/csharp/utility/MakePoint.cs +65 -2
- package/project/.sdk/tm/dart/lib/feature/test/TestFeature.dart +34 -4
- package/project/.sdk/tm/dart/lib/utility/MakePointUtility.dart +48 -2
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +70 -10
- package/project/.sdk/tm/go/feature/test_feature.go +34 -2
- package/project/.sdk/tm/go/utility/make_point.go +66 -2
- package/project/.sdk/tm/java/feature/TestFeature.java +42 -2
- package/project/.sdk/tm/java/utility/MakePoint.java +61 -2
- package/project/.sdk/tm/js/src/feature/test/TestFeature.js +22 -3
- package/project/.sdk/tm/js/src/utility/MakePointUtility.js +72 -2
- package/project/.sdk/tm/kotlin/feature/TestFeature.kt +31 -2
- package/project/.sdk/tm/kotlin/utility/MakePoint.kt +58 -2
- package/project/.sdk/tm/lean/src/SdkUtility.lean +28 -0
- package/project/.sdk/tm/lua/utility/make_point.lua +65 -2
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +40 -2
- package/project/.sdk/tm/perl/utility/make_point.pm +55 -2
- package/project/.sdk/tm/php/feature/TestFeature.php +30 -1
- package/project/.sdk/tm/php/utility/MakePoint.php +49 -1
- package/project/.sdk/tm/py/pkg/utility/make_point.py +56 -2
- package/project/.sdk/tm/rb/utility/make_point.rb +42 -2
- package/project/.sdk/tm/rust/utility/make_point.rs +69 -2
- package/project/.sdk/tm/scala/feature/TestFeature.scala +36 -1
- package/project/.sdk/tm/scala/utility/Make.scala +57 -3
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/TestFeature.swift +29 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Make.swift +51 -2
- package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +22 -3
- package/project/.sdk/tm/ts/src/utility/MakePointUtility.ts +72 -2
- package/project/.sdk/tm/zig/core/utility.zig +66 -3
- package/project/sdkgen-package.json +1 -2
- package/src/cmp/ExternalTarget.ts +1 -1
- package/src/helpers/naming.ts +129 -5
- package/src/helpers/opShape.ts +85 -0
- package/src/helpers/packageMeta.ts +59 -20
- package/src/sdkgen.ts +68 -20
- package/src/testkit.ts +863 -0
- package/testkit.d.ts +3 -0
- package/testkit.js +12 -0
- package/project/.sdk/model/target/haskell.aontu +0 -72
- package/project/.sdk/src/cmp/haskell/Config_haskell.ts +0 -98
- package/project/.sdk/src/cmp/haskell/Entity_haskell.ts +0 -13
- package/project/.sdk/src/cmp/haskell/Gitignore_haskell.ts +0 -27
- package/project/.sdk/src/cmp/haskell/Main_haskell.ts +0 -123
- package/project/.sdk/src/cmp/haskell/Package_haskell.ts +0 -60
- package/project/.sdk/src/cmp/haskell/ReadmeEntity_haskell.ts +0 -186
- package/project/.sdk/src/cmp/haskell/ReadmeExamplesTest_haskell.ts +0 -135
- package/project/.sdk/src/cmp/haskell/ReadmeExplanation_haskell.ts +0 -48
- package/project/.sdk/src/cmp/haskell/ReadmeHowto_haskell.ts +0 -168
- package/project/.sdk/src/cmp/haskell/ReadmeInstall_haskell.ts +0 -51
- package/project/.sdk/src/cmp/haskell/ReadmeIntro_haskell.ts +0 -67
- package/project/.sdk/src/cmp/haskell/ReadmeModel_haskell.ts +0 -162
- package/project/.sdk/src/cmp/haskell/ReadmeOptions_haskell.ts +0 -74
- package/project/.sdk/src/cmp/haskell/ReadmeQuick_haskell.ts +0 -241
- package/project/.sdk/src/cmp/haskell/ReadmeRef_haskell.ts +0 -408
- package/project/.sdk/src/cmp/haskell/ReadmeTopHowto_haskell.ts +0 -31
- package/project/.sdk/src/cmp/haskell/ReadmeTopQuick_haskell.ts +0 -104
- package/project/.sdk/src/cmp/haskell/ReadmeTopTest_haskell.ts +0 -80
- package/project/.sdk/src/cmp/haskell/Test_haskell.ts +0 -300
- package/project/.sdk/src/cmp/haskell/tsconfig.json +0 -15
- package/project/.sdk/src/cmp/haskell/utility_haskell.ts +0 -166
- package/project/.sdk/tm/haskell/LICENSE +0 -21
- package/project/.sdk/tm/haskell/Makefile +0 -22
- package/project/.sdk/tm/haskell/VERSION +0 -1
- package/project/.sdk/tm/haskell/src/SdkFeatures.hs +0 -1440
- package/project/.sdk/tm/haskell/src/SdkHelpers.hs +0 -337
- package/project/.sdk/tm/haskell/src/SdkJson.hs +0 -111
- package/project/.sdk/tm/haskell/src/SdkRuntime.hs +0 -1219
- package/project/.sdk/tm/haskell/src/SdkTypes.hs +0 -195
- package/project/.sdk/tm/haskell/src/VoxgigStruct.hs +0 -2299
- package/project/.sdk/tm/haskell/src/Vregex.hs +0 -237
- package/project/.sdk/tm/haskell/src/feature/README.md +0 -5
- package/project/.sdk/tm/haskell/src/feature/audit/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/base/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/cache/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/clienttrack/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/debug/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/idempotency/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/log/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/metrics/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/netsim/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/paging/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/proxy/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/ratelimit/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/rbac/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/retry/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/streaming/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/telemetry/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/test/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/timeout/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/test/Harness.hs +0 -281
- package/project/.sdk/tm/haskell/test/Runner.hs +0 -47
- package/project/.sdk/tm/haskell/test/StructCorpus.hs +0 -449
- package/project/.sdk/tm/haskell/test/TCustomUtility.hs +0 -38
- package/project/.sdk/tm/haskell/test/TFeature.hs +0 -794
- package/project/.sdk/tm/haskell/test/TNetsim.hs +0 -50
- package/project/.sdk/tm/haskell/test/TPipeline.hs +0 -334
- package/project/.sdk/tm/haskell/test/TPrimaryUtility.hs +0 -386
- package/project/.sdk/tm/haskell/test/Testutil.hs +0 -59
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from '@voxgig/apidef'
|
|
15
15
|
|
|
16
16
|
import { Tests, Scripts, Workflow, Readme, Docs } from './Extras_seneca-provider'
|
|
17
|
+
import { Gitignore } from './Gitignore_seneca-provider'
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
// The `seneca-provider` target: a Seneca plugin exposing this API's entities
|
|
@@ -206,9 +207,10 @@ function parentEntityOf(key: string, names: string[]): string {
|
|
|
206
207
|
// published package to the SDK instead.
|
|
207
208
|
//
|
|
208
209
|
// Order: the project's `output: repo`, else the Seneca convention.
|
|
209
|
-
function providerRepo(model: any, lower: string
|
|
210
|
+
function providerRepo(model: any, lower: string, tname: string):
|
|
211
|
+
{ url: string, path: string } {
|
|
210
212
|
const host = model?.main?.[KIT]?.repo?.host || 'github.com'
|
|
211
|
-
const declared = model?.main?.[KIT]?.target?.[
|
|
213
|
+
const declared = model?.main?.[KIT]?.target?.[tname]?.output?.repo
|
|
212
214
|
const path = null != declared && '' !== declared ?
|
|
213
215
|
String(declared) : `senecajs/seneca-${lower}-provider`
|
|
214
216
|
|
|
@@ -219,8 +221,8 @@ function providerRepo(model: any, lower: string): { url: string, path: string }
|
|
|
219
221
|
// The provider's published package name: the project's pin when it has one,
|
|
220
222
|
// else `@seneca/<name>-provider`. packageName() cannot answer this — its
|
|
221
223
|
// derivations are all SDK-shaped (`@<origin>/<slug>-sdk`).
|
|
222
|
-
function providerPackage(model: any, lower: string): string {
|
|
223
|
-
const declared = model?.main?.[KIT]?.target?.[
|
|
224
|
+
function providerPackage(model: any, lower: string, tname: string): string {
|
|
225
|
+
const declared = model?.main?.[KIT]?.target?.[tname]
|
|
224
226
|
?.publish?.registry?.package
|
|
225
227
|
return null != declared && '' !== declared ?
|
|
226
228
|
String(declared) : `@seneca/${lower}-provider`
|
|
@@ -253,6 +255,8 @@ const Main = cmp(function Main(props: any) {
|
|
|
253
255
|
// The SDK is a PUBLISHED dependency, not a path: this package lives in its
|
|
254
256
|
// own repo. Its name is whatever the ts target publishes under, pin
|
|
255
257
|
// included, so the two can never disagree.
|
|
258
|
+
// The TypeScript SDK this provider WRAPS — a different target, so it
|
|
259
|
+
// keeps its own name and does not follow this provider's alias.
|
|
256
260
|
const sdkPkg = packageName(model, 'npm')
|
|
257
261
|
const sdkVersion = packageVersion(model, 'ts')
|
|
258
262
|
|
|
@@ -374,7 +378,7 @@ const Main = cmp(function Main(props: any) {
|
|
|
374
378
|
'all. Remove the target, or add an entity with CRUD ops.')
|
|
375
379
|
}
|
|
376
380
|
|
|
377
|
-
const repo = providerRepo(model, lower)
|
|
381
|
+
const repo = providerRepo(model, lower, target.name)
|
|
378
382
|
|
|
379
383
|
// The companion test server lives in the SDK repo's `app/` and is NOT
|
|
380
384
|
// published, so the only way to reach it is the local checkout. The path
|
|
@@ -440,7 +444,7 @@ const Main = cmp(function Main(props: any) {
|
|
|
440
444
|
// The provider's OWN published name. Not derived from the SDK slug the
|
|
441
445
|
// way a language target's is — a provider is `@seneca/<name>-provider` —
|
|
442
446
|
// so read the project's pin directly and default to that shape.
|
|
443
|
-
pkgName: providerPackage(model, lower),
|
|
447
|
+
pkgName: providerPackage(model, lower, target.name),
|
|
444
448
|
// Whether this API authenticates at all. Decides if the plugin plumbs a
|
|
445
449
|
// credential: the SDK's auth stage emits nothing for an auth-inactive
|
|
446
450
|
// model and strips the authorization header regardless of options, so
|
|
@@ -448,14 +452,20 @@ const Main = cmp(function Main(props: any) {
|
|
|
448
452
|
authActive: isAuthActive(model),
|
|
449
453
|
}
|
|
450
454
|
|
|
451
|
-
//
|
|
452
|
-
//
|
|
455
|
+
// `.gitignore` is EMITTED rather than copied — npm strips that filename
|
|
456
|
+
// from the tarball, so as a template it reached only checkout users. See
|
|
457
|
+
// Gitignore_seneca-provider. Called before the Copy, as every language
|
|
458
|
+
// target calls its own.
|
|
459
|
+
Gitignore({})
|
|
460
|
+
|
|
461
|
+
// Static furniture: LICENSE, CODE_OF_CONDUCT, Makefile, tsfmt.json and
|
|
462
|
+
// both tsconfigs. Same for every provider.
|
|
453
463
|
Copy({
|
|
454
464
|
from: 'tm/' + target.name,
|
|
455
465
|
replace: { ...ctx$.stdrep },
|
|
456
466
|
})
|
|
457
467
|
|
|
458
|
-
PackageJson({ provider })
|
|
468
|
+
PackageJson({ provider, target })
|
|
459
469
|
ProviderSource({ provider })
|
|
460
470
|
ProviderDoc({ provider })
|
|
461
471
|
Tests({ provider })
|
|
@@ -469,9 +479,8 @@ const Main = cmp(function Main(props: any) {
|
|
|
469
479
|
// --- package.json -----------------------------------------------------------
|
|
470
480
|
|
|
471
481
|
const PackageJson = cmp(function PackageJson(props: any) {
|
|
472
|
-
const { provider } = props
|
|
482
|
+
const { provider, target } = props
|
|
473
483
|
const { model } = props.ctx$
|
|
474
|
-
const target = model.main[KIT].target['seneca-provider']
|
|
475
484
|
|
|
476
485
|
const deps = collectDeps(model, target.name, target.deps, props.ctx$.log)
|
|
477
486
|
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
KIT,
|
|
4
|
-
getModelPath
|
|
5
|
-
} from '@voxgig/apidef'
|
|
6
|
-
|
|
7
2
|
import type {
|
|
8
3
|
ModelEntity
|
|
9
4
|
} from '@voxgig/apidef'
|
|
10
5
|
|
|
11
|
-
import { cmp, each, Folder } from '@voxgig/sdkgen'
|
|
6
|
+
import { cmp, each, Folder, entityCollection } from '@voxgig/sdkgen'
|
|
12
7
|
|
|
13
8
|
|
|
14
9
|
import { TestEntity } from './TestEntity_swift'
|
|
@@ -26,7 +21,10 @@ const Test = cmp(function Test(props: any) {
|
|
|
26
21
|
// are generated here.
|
|
27
22
|
Folder({ name: 'Tests' }, () => {
|
|
28
23
|
Folder({ name: 'ProjectNameSDKTests' }, () => {
|
|
29
|
-
each(
|
|
24
|
+
const entity = each(entityCollection(model))
|
|
25
|
+
.filter((e: any) => false !== e.active)
|
|
26
|
+
|
|
27
|
+
each(entity, (entity: ModelEntity) => {
|
|
30
28
|
TestEntity({ target, entity })
|
|
31
29
|
TestDirect({ target, entity })
|
|
32
30
|
})
|
|
@@ -61,7 +61,7 @@ const Package = cmp(async function Package(props: any) {
|
|
|
61
61
|
const { repoUrl, issuesUrl } = repoInfo(model)
|
|
62
62
|
|
|
63
63
|
const pkg = {
|
|
64
|
-
name: packageName(model,
|
|
64
|
+
name: packageName(model, target.name),
|
|
65
65
|
version: packageVersion(model, target.name),
|
|
66
66
|
description: pkgDescription(model, target.name),
|
|
67
67
|
keywords: keywords(model),
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
KIT,
|
|
4
|
-
getModelPath
|
|
5
|
-
} from '@voxgig/apidef'
|
|
6
|
-
|
|
7
2
|
import type {
|
|
8
3
|
ModelEntity
|
|
9
4
|
} from '@voxgig/apidef'
|
|
10
5
|
|
|
11
|
-
import { cmp, each, Folder } from '@voxgig/sdkgen'
|
|
6
|
+
import { cmp, each, Folder, entityCollection } from '@voxgig/sdkgen'
|
|
12
7
|
|
|
13
8
|
|
|
14
9
|
// import { Quick } from './Quick_ts'
|
|
@@ -31,7 +26,13 @@ const Test = cmp(function Test(props: any) {
|
|
|
31
26
|
ReadmeExamplesTest({ target })
|
|
32
27
|
|
|
33
28
|
Folder({ name: 'entity' }, () => {
|
|
34
|
-
|
|
29
|
+
// entityCollection is the cached, UNFILTERED collection (AGENTS.md), so
|
|
30
|
+
// the active filter the raw model read this replaced never applied is
|
|
31
|
+
// written out here. Tests follow Main: an inactive entity has no source.
|
|
32
|
+
const entity = each(entityCollection(model))
|
|
33
|
+
.filter((e: any) => false !== e.active)
|
|
34
|
+
|
|
35
|
+
each(entity, (entity: ModelEntity) => {
|
|
35
36
|
TestEntity({ target, entity })
|
|
36
37
|
TestDirect({ target, entity })
|
|
37
38
|
})
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
KIT,
|
|
4
|
-
getModelPath
|
|
5
|
-
} from '@voxgig/apidef'
|
|
6
|
-
|
|
7
2
|
import type {
|
|
8
3
|
ModelEntity
|
|
9
4
|
} from '@voxgig/apidef'
|
|
10
5
|
|
|
11
|
-
import { cmp, each, Folder, File, Content } from '@voxgig/sdkgen'
|
|
6
|
+
import { cmp, each, Folder, File, Content, entityCollection } from '@voxgig/sdkgen'
|
|
12
7
|
|
|
13
8
|
import { TestEntity } from './TestEntity_zig'
|
|
14
9
|
import { TestDirect } from './TestDirect_zig'
|
|
@@ -30,7 +25,8 @@ const Test = cmp(function Test(props: any) {
|
|
|
30
25
|
const { model } = props.ctx$
|
|
31
26
|
const { target } = props
|
|
32
27
|
|
|
33
|
-
const entity =
|
|
28
|
+
const entity = each(entityCollection(model))
|
|
29
|
+
.filter((e: any) => false !== e.active)
|
|
34
30
|
|
|
35
31
|
Folder({ name: 'test' }, () => {
|
|
36
32
|
File({ name: 'generated_test.' + target.ext }, () => {
|
|
@@ -13,6 +13,29 @@ static voxgig_value* get_elem_i(voxgig_value* list, int64_t i) {
|
|
|
13
13
|
return r ? r : voxgig_new_undef();
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
// How many path segments a point has.
|
|
17
|
+
static size_t parts_len(voxgig_value* point) {
|
|
18
|
+
voxgig_value* parts = getp(point, "parts");
|
|
19
|
+
return voxgig_is_list(parts) ? voxgig_as_list(parts)->len : 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Does this point's path end in a parameter? A record route ends in the
|
|
23
|
+
// record's identifier (/boards/{id}); a cross-reference that also returns
|
|
24
|
+
// the entity ends in the relationship's name (/posts/{id}/author). That,
|
|
25
|
+
// then fewest segments, is what tells the entity's own route from a
|
|
26
|
+
// cross-reference. The same rule runs at generation time, in
|
|
27
|
+
// helpers/opShape.ts — both sides must move together.
|
|
28
|
+
static bool terminal_param(voxgig_value* point) {
|
|
29
|
+
voxgig_value* parts = getp(point, "parts");
|
|
30
|
+
if (!voxgig_is_list(parts)) return false;
|
|
31
|
+
voxgig_list* pl = voxgig_as_list(parts);
|
|
32
|
+
if (0 == pl->len) return false;
|
|
33
|
+
voxgig_value* last = pl->items[pl->len - 1];
|
|
34
|
+
if (!voxgig_is_string(last)) return false;
|
|
35
|
+
const char* s = voxgig_as_string(last);
|
|
36
|
+
return NULL != s && '{' == s[0];
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
voxgig_value* make_point_util(Context* ctx, PNError** err) {
|
|
17
40
|
*err = NULL;
|
|
18
41
|
|
|
@@ -58,9 +81,10 @@ voxgig_value* make_point_util(Context* ctx, PNError** err) {
|
|
|
58
81
|
voxgig_value* selector = is_data ? ctx->data : ctx->mtch;
|
|
59
82
|
|
|
60
83
|
voxgig_value* point = voxgig_new_undef();
|
|
84
|
+
bool matched = false;
|
|
61
85
|
for (int64_t i = 0; i < plen; i++) {
|
|
62
|
-
|
|
63
|
-
voxgig_value* select_def = to_map(getp(
|
|
86
|
+
voxgig_value* cand = get_elem_i(points, i);
|
|
87
|
+
voxgig_value* select_def = to_map(getp(cand, "select"));
|
|
64
88
|
bool found = true;
|
|
65
89
|
|
|
66
90
|
if (!v_is_noval(selector) && !v_is_noval(select_def)) {
|
|
@@ -85,7 +109,44 @@ voxgig_value* make_point_util(Context* ctx, PNError** err) {
|
|
|
85
109
|
if (!v_eq(req_action, select_action)) found = false;
|
|
86
110
|
}
|
|
87
111
|
|
|
88
|
-
if (found)
|
|
112
|
+
if (found) {
|
|
113
|
+
point = cand;
|
|
114
|
+
matched = true;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// select.exist can list more than the params needed to pick a point, so
|
|
120
|
+
// nothing matches — fall back to the entity's own route rather than
|
|
121
|
+
// whichever point came last.
|
|
122
|
+
if (!matched) {
|
|
123
|
+
// A request naming an action reaches here only because that action's
|
|
124
|
+
// own point failed its exist test, so it is unbuildable whatever we
|
|
125
|
+
// pick. Refuse it BEFORE choosing a fallback: the guard below compares
|
|
126
|
+
// the chosen point's $action and would wave the request through
|
|
127
|
+
// whenever the fallback lands on the action point itself.
|
|
128
|
+
voxgig_value* unmatched_action = getp(reqselector, "$action");
|
|
129
|
+
if (!v_is_noval(unmatched_action)) {
|
|
130
|
+
char* actstr = voxgig_stringify(unmatched_action, -1);
|
|
131
|
+
char buf[512];
|
|
132
|
+
snprintf(buf, sizeof(buf), "Operation \"%s\" action \"%s\" is not valid.",
|
|
133
|
+
op->name, actstr ? actstr : "");
|
|
134
|
+
*err = context_make_error(ctx, "point_action_invalid", buf);
|
|
135
|
+
return NULL;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
point = get_elem_i(points, 0);
|
|
139
|
+
for (int64_t i = 0; i < plen; i++) {
|
|
140
|
+
voxgig_value* cand = get_elem_i(points, i);
|
|
141
|
+
bool cand_term = terminal_param(cand);
|
|
142
|
+
bool best_term = terminal_param(point);
|
|
143
|
+
if (cand_term != best_term) {
|
|
144
|
+
if (cand_term) point = cand;
|
|
145
|
+
}
|
|
146
|
+
else if (parts_len(cand) < parts_len(point)) {
|
|
147
|
+
point = cand;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
89
150
|
}
|
|
90
151
|
|
|
91
152
|
voxgig_value* req_action = getp(reqselector, "$action");
|
|
@@ -641,21 +641,56 @@
|
|
|
641
641
|
sa (vs/getprop select-def "$action")]
|
|
642
642
|
(when (not= ra sa) (reset! found false))))
|
|
643
643
|
@found))
|
|
644
|
-
;;
|
|
645
|
-
;;
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
644
|
+
;; How many path segments a point has, and whether its path
|
|
645
|
+
;; ends in a parameter. A record route ends in the record's
|
|
646
|
+
;; identifier (/boards/{id}); a cross-reference that also
|
|
647
|
+
;; returns the entity ends in the relationship's name
|
|
648
|
+
;; (/posts/{id}/author). That, then fewest segments, is what
|
|
649
|
+
;; tells the entity's own route from a cross-reference. The
|
|
650
|
+
;; same rule runs at generation time, in helpers/opShape.ts —
|
|
651
|
+
;; both sides must move together.
|
|
652
|
+
parts-len (fn [p]
|
|
653
|
+
(let [parts (vs/getprop p "parts")]
|
|
654
|
+
(if (vs/islist parts) (vs/size parts) 0)))
|
|
655
|
+
terminal-param? (fn [p]
|
|
656
|
+
(let [parts (vs/getprop p "parts")]
|
|
657
|
+
(and (vs/islist parts)
|
|
658
|
+
(pos? (vs/size parts))
|
|
659
|
+
(let [last-part (vs/getelem parts (dec (vs/size parts)))]
|
|
660
|
+
(and (string? last-part)
|
|
661
|
+
(str/starts-with? last-part "{"))))))
|
|
662
|
+
own-point (fn [ps]
|
|
663
|
+
(reduce (fn [best cand]
|
|
664
|
+
(let [ct (terminal-param? cand)
|
|
665
|
+
bt (terminal-param? best)]
|
|
666
|
+
(if (not= ct bt)
|
|
667
|
+
(if ct cand best)
|
|
668
|
+
(if (< (parts-len cand) (parts-len best)) cand best))))
|
|
669
|
+
(first ps) ps))
|
|
670
|
+
matched (first (filter point-matches? (vec (op-points op))))
|
|
650
671
|
req-action (vs/getprop reqselector "$action")]
|
|
651
|
-
(
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
672
|
+
(cond
|
|
673
|
+
;; select.exist can list more than the params needed to pick a
|
|
674
|
+
;; point, so nothing matches. A request naming an action reaches
|
|
675
|
+
;; here only because that action's own point failed its exist
|
|
676
|
+
;; test, so it is unbuildable whatever we pick — refuse it
|
|
677
|
+
;; BEFORE falling back, since the guard below compares the
|
|
678
|
+
;; chosen point's $action and would wave the request through
|
|
679
|
+
;; whenever the fallback lands on the action point itself.
|
|
680
|
+
(and (nil? matched) reqselector req-action)
|
|
681
|
+
[nil (ctx-error ctx "point_action_invalid"
|
|
682
|
+
(str "Operation \"" (op-name op) "\" action \"" (vs/stringify req-action) "\" is not valid."))]
|
|
683
|
+
|
|
684
|
+
:else
|
|
685
|
+
(let [chosen (or matched (own-point (vec (op-points op))))]
|
|
686
|
+
(if (and reqselector req-action chosen)
|
|
687
|
+
(let [point-select (to-map (vs/getprop chosen "select"))
|
|
688
|
+
point-action (vs/getprop point-select "$action")]
|
|
689
|
+
(if (not= req-action point-action)
|
|
690
|
+
[nil (ctx-error ctx "point_action_invalid"
|
|
691
|
+
(str "Operation \"" (op-name op) "\" action \"" (vs/stringify req-action) "\" is not valid."))]
|
|
692
|
+
(do (oset! ctx :point chosen) [(oget ctx :point) nil])))
|
|
693
|
+
(do (oset! ctx :point chosen) [(oget ctx :point) nil]))))))))))
|
|
659
694
|
|
|
660
695
|
(defn u-make-spec [ctx]
|
|
661
696
|
(if (some? (out-get ctx "spec"))
|
|
@@ -330,9 +330,10 @@ inline Value makePoint(CtxPtr ctx) {
|
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
Value point;
|
|
333
|
+
bool matched = false;
|
|
333
334
|
for (size_t i = 0; i < op->points.size(); i++) {
|
|
334
|
-
|
|
335
|
-
Value selectDef = Helpers::toMapAny(getp(
|
|
335
|
+
Value cand = op->points[i];
|
|
336
|
+
Value selectDef = Helpers::toMapAny(getp(cand, "select"));
|
|
336
337
|
bool found = true;
|
|
337
338
|
|
|
338
339
|
if (selector.is_map() && selectDef.is_map()) {
|
|
@@ -356,7 +357,58 @@ inline Value makePoint(CtxPtr ctx) {
|
|
|
356
357
|
if (reqAction != selectAction) found = false;
|
|
357
358
|
}
|
|
358
359
|
|
|
359
|
-
if (found)
|
|
360
|
+
if (found) {
|
|
361
|
+
point = cand;
|
|
362
|
+
matched = true;
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// select.exist can list more than the params needed to pick a point (for
|
|
368
|
+
// /boards/{id} it is Trello's 17 optional query-includes), so a plain
|
|
369
|
+
// {id} call matches NOTHING. Fall back to the entity's own route rather
|
|
370
|
+
// than whichever point came last.
|
|
371
|
+
if (!matched) {
|
|
372
|
+
// A request naming an action reaches here only because that action's
|
|
373
|
+
// own point failed its exist test, so it is unbuildable whatever we
|
|
374
|
+
// pick. Refuse it BEFORE choosing a fallback: the guard below compares
|
|
375
|
+
// the chosen point's $action and would wave the request through
|
|
376
|
+
// whenever the fallback lands on the action point itself.
|
|
377
|
+
Value unmatchedAction = getp(reqselector, "$action", Value(nullptr));
|
|
378
|
+
if (!unmatchedAction.is_null()) {
|
|
379
|
+
throw ctx->makeError("point_action_invalid",
|
|
380
|
+
"Operation \"" + op->name + "\" action \"" +
|
|
381
|
+
Struct::stringify(unmatchedAction) + "\" is not valid.");
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// A terminal parameter marks a record route (/boards/{id}); a
|
|
385
|
+
// cross-reference ends in the relationship's name (/posts/{id}/author).
|
|
386
|
+
// Failing that, the shallower path wins. The same rule runs at
|
|
387
|
+
// generation time, in helpers/opShape.ts — both sides must move
|
|
388
|
+
// together.
|
|
389
|
+
auto partsLen = [](const Value& p) -> size_t {
|
|
390
|
+
Value parts = getp(p, "parts");
|
|
391
|
+
return parts.is_list() ? parts.as_list()->size() : 0;
|
|
392
|
+
};
|
|
393
|
+
auto terminalParam = [](const Value& p) -> bool {
|
|
394
|
+
Value parts = getp(p, "parts");
|
|
395
|
+
if (!parts.is_list() || parts.as_list()->empty()) return false;
|
|
396
|
+
const Value& last = parts.as_list()->back();
|
|
397
|
+
return last.is_string() && 0 == last.as_string().rfind("{", 0);
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
point = op->points[0];
|
|
401
|
+
for (size_t i = 0; i < op->points.size(); i++) {
|
|
402
|
+
const Value& cand = op->points[i];
|
|
403
|
+
bool candTerm = terminalParam(cand);
|
|
404
|
+
bool bestTerm = terminalParam(point);
|
|
405
|
+
if (candTerm != bestTerm) {
|
|
406
|
+
if (candTerm) point = cand;
|
|
407
|
+
}
|
|
408
|
+
else if (partsLen(cand) < partsLen(point)) {
|
|
409
|
+
point = cand;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
360
412
|
}
|
|
361
413
|
|
|
362
414
|
if (reqselector.is_map()) {
|
|
@@ -313,10 +313,44 @@ public class TestFeature : BaseFeature
|
|
|
313
313
|
{
|
|
314
314
|
var opname = op.Name;
|
|
315
315
|
|
|
316
|
-
//
|
|
316
|
+
// Pick the entity's own endpoint from config, not a cross-reference
|
|
317
|
+
// from another resource that also returns it — the same rule
|
|
318
|
+
// MakePoint falls back to, so the seed-data query is built from the
|
|
319
|
+
// endpoint the request will actually be sent to: a terminal `{id}`
|
|
320
|
+
// marks a record route, and failing that the shallower path wins.
|
|
317
321
|
var points = StructUtils.GetPath(ctx.Config,
|
|
318
322
|
StructUtils.Jt("entity", ctx.Entity!.GetName(), "op", opname, "points"));
|
|
319
|
-
var point = StructUtils.GetElem(points,
|
|
323
|
+
var point = StructUtils.GetElem(points, 0);
|
|
324
|
+
if (points is List<object?> pointList)
|
|
325
|
+
{
|
|
326
|
+
static int PointPartsLen(object? p) =>
|
|
327
|
+
StructUtils.GetProp(p, "parts") is List<object?> parts ? parts.Count : 0;
|
|
328
|
+
static bool PointTerminalParam(object? p)
|
|
329
|
+
{
|
|
330
|
+
if (StructUtils.GetProp(p, "parts") is not List<object?> parts || parts.Count == 0)
|
|
331
|
+
{
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
return parts[parts.Count - 1] is string last && last.StartsWith("{");
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
foreach (var candidate in pointList)
|
|
338
|
+
{
|
|
339
|
+
var candTerm = PointTerminalParam(candidate);
|
|
340
|
+
var bestTerm = PointTerminalParam(point);
|
|
341
|
+
if (candTerm != bestTerm)
|
|
342
|
+
{
|
|
343
|
+
if (candTerm)
|
|
344
|
+
{
|
|
345
|
+
point = candidate;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
else if (PointPartsLen(candidate) < PointPartsLen(point))
|
|
349
|
+
{
|
|
350
|
+
point = candidate;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
320
354
|
|
|
321
355
|
// Get required params.
|
|
322
356
|
var paramsPath = StructUtils.GetPath(point, StructUtils.Jt("args", "params"));
|
|
@@ -6,6 +6,27 @@ namespace ProjectNameSdk.Util;
|
|
|
6
6
|
|
|
7
7
|
public static partial class SdkUtility
|
|
8
8
|
{
|
|
9
|
+
// How many path segments a point has.
|
|
10
|
+
private static int PartsLen(Dictionary<string, object?>? point)
|
|
11
|
+
{
|
|
12
|
+
return StructUtils.GetProp(point, "parts") is List<object?> parts ? parts.Count : 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Does this point's path end in a parameter? A record route ends in the
|
|
16
|
+
// record's identifier (/boards/{id}); a cross-reference that also returns
|
|
17
|
+
// the entity ends in the relationship's name (/posts/{id}/author). That,
|
|
18
|
+
// then fewest segments, is what tells the entity's own route from a
|
|
19
|
+
// cross-reference. The same rule runs at generation time, in
|
|
20
|
+
// helpers/opShape.ts — both sides must move together.
|
|
21
|
+
private static bool TerminalParam(Dictionary<string, object?>? point)
|
|
22
|
+
{
|
|
23
|
+
if (StructUtils.GetProp(point, "parts") is not List<object?> parts || parts.Count == 0)
|
|
24
|
+
{
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return parts[parts.Count - 1] is string last && last.StartsWith("{");
|
|
28
|
+
}
|
|
29
|
+
|
|
9
30
|
internal static Dictionary<string, object?>? MakePointUtil(Context ctx)
|
|
10
31
|
{
|
|
11
32
|
if (ctx.Out.TryGetValue("point", out var outPoint) && outPoint != null)
|
|
@@ -62,10 +83,10 @@ public static partial class SdkUtility
|
|
|
62
83
|
}
|
|
63
84
|
|
|
64
85
|
Dictionary<string, object?>? point = null;
|
|
86
|
+
var matched = false;
|
|
65
87
|
foreach (var candidate in op.Points)
|
|
66
88
|
{
|
|
67
|
-
|
|
68
|
-
var selectDef = Helpers.ToMapAny(StructUtils.GetProp(point, "select"));
|
|
89
|
+
var selectDef = Helpers.ToMapAny(StructUtils.GetProp(candidate, "select"));
|
|
69
90
|
var found = true;
|
|
70
91
|
|
|
71
92
|
if (selector != null && selectDef != null)
|
|
@@ -98,10 +119,52 @@ public static partial class SdkUtility
|
|
|
98
119
|
|
|
99
120
|
if (found)
|
|
100
121
|
{
|
|
122
|
+
point = candidate;
|
|
123
|
+
matched = true;
|
|
101
124
|
break;
|
|
102
125
|
}
|
|
103
126
|
}
|
|
104
127
|
|
|
128
|
+
// select.exist can list more than the params needed to pick a
|
|
129
|
+
// point, so nothing matches — fall back to the entity's own
|
|
130
|
+
// route rather than the last point.
|
|
131
|
+
if (!matched)
|
|
132
|
+
{
|
|
133
|
+
// A request naming an action reaches here only because that
|
|
134
|
+
// action's own point failed its exist test, so it is
|
|
135
|
+
// unbuildable whatever we pick. Refuse it BEFORE choosing a
|
|
136
|
+
// fallback: the guard below compares the chosen point's
|
|
137
|
+
// $action and would wave the request through whenever the
|
|
138
|
+
// fallback lands on the action point itself.
|
|
139
|
+
var unmatchedAction = reqselector != null
|
|
140
|
+
? StructUtils.GetProp(reqselector, "$action") : null;
|
|
141
|
+
if (unmatchedAction != null)
|
|
142
|
+
{
|
|
143
|
+
throw ctx.MakeError("point_action_invalid",
|
|
144
|
+
"Operation \"" + op.Name +
|
|
145
|
+
"\" action \"" + StructUtils.Stringify(unmatchedAction) +
|
|
146
|
+
"\" is not valid.");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
point = op.Points[0];
|
|
150
|
+
foreach (var candidate in op.Points)
|
|
151
|
+
{
|
|
152
|
+
var candTerm = TerminalParam(candidate);
|
|
153
|
+
var bestTerm = TerminalParam(point);
|
|
154
|
+
if (candTerm != bestTerm)
|
|
155
|
+
{
|
|
156
|
+
if (candTerm)
|
|
157
|
+
{
|
|
158
|
+
point = candidate;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else if (PartsLen(candidate) < PartsLen(point))
|
|
162
|
+
{
|
|
163
|
+
point = candidate;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
105
168
|
if (reqselector != null)
|
|
106
169
|
{
|
|
107
170
|
var reqAction = StructUtils.GetProp(reqselector, "$action");
|
|
@@ -214,10 +214,40 @@ class TestFeature extends BaseFeature {
|
|
|
214
214
|
final param = ctx.utility.param;
|
|
215
215
|
|
|
216
216
|
final opname = op.name;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
217
|
+
|
|
218
|
+
// Pick the entity's own endpoint from config, not a cross-reference from
|
|
219
|
+
// another resource that also returns it — the same rule makePoint falls
|
|
220
|
+
// back to, so the seed-data query is built from the endpoint the request
|
|
221
|
+
// will actually be sent to: a terminal `{id}` marks a record route, and
|
|
222
|
+
// failing that the shallower path wins.
|
|
223
|
+
final points = vs.getpath(
|
|
224
|
+
ctx.config, ['entity', _entname(ctx.entity), 'op', opname, 'points']);
|
|
225
|
+
var point = vs.getelem(points, 0);
|
|
226
|
+
if (points is List) {
|
|
227
|
+
int pointPartsLen(dynamic p) {
|
|
228
|
+
final parts = vs.getprop(p, 'parts');
|
|
229
|
+
return parts is List ? parts.length : 0;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
bool pointTerminalParam(dynamic p) {
|
|
233
|
+
final parts = vs.getprop(p, 'parts');
|
|
234
|
+
if (parts is! List || parts.isEmpty) {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
final last = parts[parts.length - 1];
|
|
238
|
+
return last is String && last.startsWith('{');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
for (final cand in points) {
|
|
242
|
+
if (pointTerminalParam(cand) != pointTerminalParam(point)) {
|
|
243
|
+
if (pointTerminalParam(cand)) {
|
|
244
|
+
point = cand;
|
|
245
|
+
}
|
|
246
|
+
} else if (pointPartsLen(cand) < pointPartsLen(point)) {
|
|
247
|
+
point = cand;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
221
251
|
|
|
222
252
|
final reqd = vs.transform(
|
|
223
253
|
vs.select(vs.getpath(point, ['args', 'params']), {'reqd': true}),
|