@voxgig/sdkgen 1.3.17 → 1.3.18
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/Entity.js +5 -1
- package/dist/cmp/Entity.js.map +1 -1
- package/dist/cmp/Feature.js +2 -1
- package/dist/cmp/Feature.js.map +1 -1
- package/dist/helpers/canonType.js +8 -3
- package/dist/helpers/canonType.js.map +1 -1
- package/dist/helpers/collectDeps.d.ts +1 -1
- package/dist/helpers/collectDeps.js +36 -13
- package/dist/helpers/collectDeps.js.map +1 -1
- package/dist/helpers/naming.d.ts +3 -1
- package/dist/helpers/naming.js +53 -0
- package/dist/helpers/naming.js.map +1 -1
- package/dist/helpers/opShape.d.ts +3 -1
- package/dist/helpers/opShape.js +87 -8
- package/dist/helpers/opShape.js.map +1 -1
- package/dist/sdkgen.d.ts +3 -3
- package/dist/sdkgen.js +6 -2
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -10
- package/project/.sdk/model/target/cpp.aontu +4 -4
- package/project/.sdk/model/target/go-cli.aontu +17 -17
- package/project/.sdk/model/target/go-mcp.aontu +11 -11
- package/project/.sdk/model/target/go.aontu +1 -1
- package/project/.sdk/model/target/java.aontu +4 -4
- package/project/.sdk/model/target/kotlin.aontu +4 -4
- package/project/.sdk/model/target/lean.aontu +51 -0
- package/project/.sdk/model/target/scala.aontu +4 -4
- package/project/.sdk/src/cmp/c/EntityTypes_c.ts +3 -4
- package/project/.sdk/src/cmp/c/Entity_c.ts +3 -3
- package/project/.sdk/src/cmp/c/ReadmeExamplesTest_c.ts +24 -7
- package/project/.sdk/src/cmp/c/TestDirect_c.ts +3 -3
- package/project/.sdk/src/cmp/c/TestEntity_c.ts +1 -1
- package/project/.sdk/src/cmp/clojure/Entity_clojure.ts +1 -1
- package/project/.sdk/src/cmp/clojure/ReadmeExamplesTest_clojure.ts +19 -8
- package/project/.sdk/src/cmp/cpp/EntityTypes_cpp.ts +2 -2
- package/project/.sdk/src/cmp/cpp/Entity_cpp.ts +3 -3
- package/project/.sdk/src/cmp/cpp/MainEntity_cpp.ts +2 -2
- package/project/.sdk/src/cmp/cpp/ReadmeExamplesTest_cpp.ts +136 -0
- package/project/.sdk/src/cmp/cpp/TestDirect_cpp.ts +3 -3
- package/project/.sdk/src/cmp/cpp/Test_cpp.ts +4 -0
- package/project/.sdk/src/cmp/csharp/EntityTypes_csharp.ts +2 -3
- package/project/.sdk/src/cmp/csharp/Entity_csharp.ts +3 -3
- package/project/.sdk/src/cmp/csharp/MainEntity_csharp.ts +2 -2
- package/project/.sdk/src/cmp/csharp/Package_csharp.ts +1 -1
- package/project/.sdk/src/cmp/csharp/ReadmeExamplesTest_csharp.ts +13 -1
- package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +3 -3
- package/project/.sdk/src/cmp/dart/EntityTypes_dart.ts +2 -3
- package/project/.sdk/src/cmp/dart/Entity_dart.ts +3 -3
- package/project/.sdk/src/cmp/dart/MainEntity_dart.ts +2 -2
- package/project/.sdk/src/cmp/dart/Main_dart.ts +3 -3
- package/project/.sdk/src/cmp/dart/Package_dart.ts +1 -1
- package/project/.sdk/src/cmp/dart/TestDirect_dart.ts +4 -4
- package/project/.sdk/src/cmp/elixir/EntityTypes_elixir.ts +2 -3
- package/project/.sdk/src/cmp/elixir/Entity_elixir.ts +1 -1
- package/project/.sdk/src/cmp/elixir/ReadmeExamplesTest_elixir.ts +21 -3
- package/project/.sdk/src/cmp/go/Config_go.ts +4 -1
- package/project/.sdk/src/cmp/go/EntityTypes_go.ts +110 -18
- package/project/.sdk/src/cmp/go/Entity_go.ts +3 -3
- package/project/.sdk/src/cmp/go/Main_go.ts +7 -6
- package/project/.sdk/src/cmp/go/Package_go.ts +1 -1
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +3 -3
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +1 -1
- package/project/.sdk/src/cmp/go/utility_go.ts +25 -0
- package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +9 -1
- package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +9 -1
- package/project/.sdk/src/cmp/haskell/ReadmeExamplesTest_haskell.ts +28 -18
- package/project/.sdk/src/cmp/java/EntityTypes_java.ts +2 -3
- package/project/.sdk/src/cmp/java/Entity_java.ts +3 -3
- package/project/.sdk/src/cmp/java/MainEntity_java.ts +2 -2
- package/project/.sdk/src/cmp/java/Package_java.ts +1 -1
- package/project/.sdk/src/cmp/java/ReadmeExamplesTest_java.ts +23 -1
- package/project/.sdk/src/cmp/java/TestDirect_java.ts +3 -3
- package/project/.sdk/src/cmp/js/EntityTypes_js.ts +2 -3
- package/project/.sdk/src/cmp/js/Entity_js.ts +3 -3
- package/project/.sdk/src/cmp/js/MainEntity_js.ts +2 -2
- package/project/.sdk/src/cmp/js/Main_js.ts +2 -2
- package/project/.sdk/src/cmp/js/TestDirect_js.ts +4 -4
- package/project/.sdk/src/cmp/kotlin/EntityTypes_kotlin.ts +2 -3
- package/project/.sdk/src/cmp/kotlin/Entity_kotlin.ts +3 -3
- package/project/.sdk/src/cmp/kotlin/MainEntity_kotlin.ts +2 -2
- package/project/.sdk/src/cmp/kotlin/Package_kotlin.ts +1 -1
- package/project/.sdk/src/cmp/kotlin/ReadmeExamplesTest_kotlin.ts +27 -2
- package/project/.sdk/src/cmp/kotlin/TestDirect_kotlin.ts +3 -3
- package/project/.sdk/src/cmp/lean/Config_lean.ts +88 -0
- package/project/.sdk/src/cmp/lean/Entity_lean.ts +9 -0
- package/project/.sdk/src/cmp/lean/Gitignore_lean.ts +18 -0
- package/project/.sdk/src/cmp/lean/Main_lean.ts +120 -0
- package/project/.sdk/src/cmp/lean/Package_lean.ts +68 -0
- package/project/.sdk/src/cmp/lean/ReadmeEntity_lean.ts +29 -0
- package/project/.sdk/src/cmp/lean/ReadmeExplanation_lean.ts +19 -0
- package/project/.sdk/src/cmp/lean/ReadmeHowto_lean.ts +25 -0
- package/project/.sdk/src/cmp/lean/ReadmeInstall_lean.ts +38 -0
- package/project/.sdk/src/cmp/lean/ReadmeIntro_lean.ts +25 -0
- package/project/.sdk/src/cmp/lean/ReadmeModel_lean.ts +24 -0
- package/project/.sdk/src/cmp/lean/ReadmeOptions_lean.ts +22 -0
- package/project/.sdk/src/cmp/lean/ReadmeQuick_lean.ts +50 -0
- package/project/.sdk/src/cmp/lean/ReadmeRef_lean.ts +16 -0
- package/project/.sdk/src/cmp/lean/ReadmeTopHowto_lean.ts +16 -0
- package/project/.sdk/src/cmp/lean/ReadmeTopQuick_lean.ts +23 -0
- package/project/.sdk/src/cmp/lean/ReadmeTopTest_lean.ts +18 -0
- package/project/.sdk/src/cmp/lean/Test_lean.ts +207 -0
- package/project/.sdk/src/cmp/lean/utility_lean.ts +78 -0
- package/project/.sdk/src/cmp/lua/EntityTypes_lua.ts +2 -3
- package/project/.sdk/src/cmp/lua/Entity_lua.ts +3 -3
- package/project/.sdk/src/cmp/lua/Package_lua.ts +1 -1
- package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +3 -3
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +1 -1
- package/project/.sdk/src/cmp/ocaml/ReadmeExamplesTest_ocaml.ts +29 -14
- package/project/.sdk/src/cmp/perl/Entity_perl.ts +3 -3
- package/project/.sdk/src/cmp/perl/MainEntity_perl.ts +2 -2
- package/project/.sdk/src/cmp/perl/Package_perl.ts +1 -1
- package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +3 -3
- package/project/.sdk/src/cmp/php/EntityTypes_php.ts +2 -3
- package/project/.sdk/src/cmp/php/Entity_php.ts +3 -3
- package/project/.sdk/src/cmp/php/MainEntity_php.ts +2 -2
- package/project/.sdk/src/cmp/php/Package_php.ts +1 -1
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +3 -3
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +1 -1
- package/project/.sdk/src/cmp/py/EntityTypes_py.ts +2 -3
- package/project/.sdk/src/cmp/py/Entity_py.ts +3 -3
- package/project/.sdk/src/cmp/py/MainEntity_py.ts +2 -2
- package/project/.sdk/src/cmp/py/Main_py.ts +2 -2
- package/project/.sdk/src/cmp/py/Package_py.ts +1 -1
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +3 -3
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +1 -1
- package/project/.sdk/src/cmp/rb/EntityTypes_rb.ts +15 -5
- package/project/.sdk/src/cmp/rb/Entity_rb.ts +3 -3
- package/project/.sdk/src/cmp/rb/MainEntity_rb.ts +2 -2
- package/project/.sdk/src/cmp/rb/Package_rb.ts +2 -2
- package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +3 -3
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +1 -1
- package/project/.sdk/src/cmp/rust/EntityBase_rust.ts +2 -2
- package/project/.sdk/src/cmp/rust/EntityTypes_rust.ts +3 -4
- package/project/.sdk/src/cmp/rust/Entity_rust.ts +3 -3
- package/project/.sdk/src/cmp/rust/MainEntity_rust.ts +2 -2
- package/project/.sdk/src/cmp/rust/Package_rust.ts +1 -1
- package/project/.sdk/src/cmp/rust/ReadmeExamplesTest_rust.ts +22 -10
- package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +3 -3
- package/project/.sdk/src/cmp/scala/EntityTypes_scala.ts +2 -3
- package/project/.sdk/src/cmp/scala/Entity_scala.ts +3 -3
- package/project/.sdk/src/cmp/scala/MainEntity_scala.ts +2 -2
- package/project/.sdk/src/cmp/scala/ReadmeExamplesTest_scala.ts +22 -3
- package/project/.sdk/src/cmp/scala/TestDirect_scala.ts +3 -3
- package/project/.sdk/src/cmp/scala/Test_scala.ts +1 -1
- package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +3 -4
- package/project/.sdk/src/cmp/swift/Entity_swift.ts +3 -3
- package/project/.sdk/src/cmp/swift/MainEntity_swift.ts +2 -2
- package/project/.sdk/src/cmp/swift/Package_swift.ts +1 -1
- package/project/.sdk/src/cmp/swift/ReadmeExamplesTest_swift.ts +18 -1
- package/project/.sdk/src/cmp/swift/TestDirect_swift.ts +1 -1
- package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +2 -3
- package/project/.sdk/src/cmp/ts/Entity_ts.ts +3 -3
- package/project/.sdk/src/cmp/ts/MainEntity_ts.ts +2 -2
- package/project/.sdk/src/cmp/ts/Main_ts.ts +2 -2
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +4 -4
- package/project/.sdk/src/cmp/zig/Entity_zig.ts +3 -3
- package/project/.sdk/src/cmp/zig/MainEntity_zig.ts +2 -2
- package/project/.sdk/src/cmp/zig/Package_zig.ts +10 -2
- package/project/.sdk/tm/cpp/test/primary_utility_test.cpp +8 -16
- package/project/.sdk/tm/csharp/test/PrimaryUtilityTest.cs +10 -28
- package/project/.sdk/tm/dart/test/primary_test.dart +7 -0
- package/project/.sdk/tm/go/feature/test_feature.go +33 -1
- package/project/.sdk/tm/go/test/primary_utility_test.go +41 -42
- package/project/.sdk/tm/go/test/runner_test.go +30 -1
- package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +7 -24
- package/project/.sdk/tm/js/src/feature/test/TestFeature.js +18 -1
- package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +8 -0
- package/project/.sdk/tm/kotlin/test/PrimaryUtilityTest.kt +7 -20
- package/project/.sdk/tm/lean/LICENSE +21 -0
- package/project/.sdk/tm/lean/VERSION +1 -0
- package/project/.sdk/tm/lean/src/SdkFeature.lean +171 -0
- package/project/.sdk/tm/lean/src/SdkFeatures.lean +602 -0
- package/project/.sdk/tm/lean/src/SdkJson.lean +134 -0
- package/project/.sdk/tm/lean/src/SdkRuntime.lean +356 -0
- package/project/.sdk/tm/lean/src/SdkUtility.lean +617 -0
- package/project/.sdk/tm/lean/src/VoxgigStruct.lean +2880 -0
- package/project/.sdk/tm/lean/src/Vregex.lean +412 -0
- package/project/.sdk/tm/lean/src/feature/README.md +5 -0
- package/project/.sdk/tm/lean/src/feature/audit/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/base/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/cache/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/clienttrack/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/debug/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/idempotency/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/log/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/metrics/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/netsim/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/paging/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/proxy/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/ratelimit/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/rbac/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/retry/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/streaming/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/telemetry/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/test/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/timeout/.gitkeep +0 -0
- package/project/.sdk/tm/lean/test/StructCorpus.lean +697 -0
- package/project/.sdk/tm/lean/test/TFeature.lean +268 -0
- package/project/.sdk/tm/lean/test/TPrimaryUtility.lean +349 -0
- package/project/.sdk/tm/lua/test/primary_utility_test.lua +10 -8
- package/project/.sdk/tm/perl/t/primary_utility.t +8 -17
- package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +9 -7
- package/project/.sdk/tm/py/feature/test_feature.py +28 -1
- package/project/.sdk/tm/py/test/test_primary_utility.py +13 -18
- package/project/.sdk/tm/rb/feature/test_feature.rb +24 -1
- package/project/.sdk/tm/rb/test/primary_utility_test.rb +7 -8
- package/project/.sdk/tm/rust/tests/common/mod.rs +37 -1
- package/project/.sdk/tm/rust/tests/primary_utility_test.rs +12 -26
- package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/PrimaryUtilityTest.swift +7 -8
- package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +18 -1
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +65 -21
- package/src/cmp/Entity.ts +5 -1
- package/src/cmp/Feature.ts +2 -1
- package/src/helpers/canonType.ts +8 -3
- package/src/helpers/collectDeps.ts +39 -12
- package/src/helpers/naming.ts +59 -0
- package/src/helpers/opShape.ts +99 -12
- package/src/sdkgen.ts +7 -3
|
@@ -4,7 +4,7 @@ import * as Path from 'node:path'
|
|
|
4
4
|
import {
|
|
5
5
|
cmp, each, camelify, names,
|
|
6
6
|
File, Content, Folder, Fragment, Line, FeatureHook, Slot,
|
|
7
|
-
entityClassName, opTypeName,
|
|
7
|
+
entityClassName, entityCollection, opTypeName,
|
|
8
8
|
} from '@voxgig/sdkgen'
|
|
9
9
|
|
|
10
10
|
import {
|
|
@@ -23,7 +23,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
23
23
|
// `<Name>Entity`, disambiguated when it would clash with another entity's
|
|
24
24
|
// data-type name. The DATA type stays `<Name>`. The snake-cased source-file
|
|
25
25
|
// name is unaffected; only the class identifier changes.
|
|
26
|
-
const entityColl =
|
|
26
|
+
const entityColl = entityCollection(model)
|
|
27
27
|
const cls = entityClassName(entity, entityColl)
|
|
28
28
|
|
|
29
29
|
const entrep = {
|
|
@@ -53,7 +53,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
53
53
|
|
|
54
54
|
File({ name: entity.name + '_entity.' + target.ext }, () => {
|
|
55
55
|
|
|
56
|
-
const opnames = Object.keys(entity.op)
|
|
56
|
+
const opnames = Object.keys(entity.op || {})
|
|
57
57
|
|
|
58
58
|
const opfrags =
|
|
59
59
|
(['load', 'list', 'create', 'update', 'remove']
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
import { cmp, Content, entityClassName } from '@voxgig/sdkgen'
|
|
3
|
+
import { cmp, Content, entityClassName, entityCollection } from '@voxgig/sdkgen'
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
KIT,
|
|
@@ -15,7 +15,7 @@ const MainEntity = cmp(async function MainEntity(props: any) {
|
|
|
15
15
|
// Return the collision-free class (entityClassName); the accessor METHOD name
|
|
16
16
|
// (entity.Name) is unchanged so callers still write client.<Name>(). The
|
|
17
17
|
// source module is snake-cased, so only the imported class identifier changes.
|
|
18
|
-
const cls = entityClassName(entity,
|
|
18
|
+
const cls = entityClassName(entity, entityCollection(model))
|
|
19
19
|
|
|
20
20
|
Content(`
|
|
21
21
|
def ${entity.Name}(self, data=None) -> "${cls}":
|
|
@@ -4,7 +4,7 @@ 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,
|
|
7
|
+
entityClassName, entityCollection,
|
|
8
8
|
} from '@voxgig/sdkgen'
|
|
9
9
|
|
|
10
10
|
|
|
@@ -94,7 +94,7 @@ from typing import TYPE_CHECKING
|
|
|
94
94
|
if TYPE_CHECKING:
|
|
95
95
|
`)
|
|
96
96
|
each(entity, (ent: any) => {
|
|
97
|
-
Content(` from entity.${ent.name}_entity import ${entityClassName(ent,
|
|
97
|
+
Content(` from entity.${ent.name}_entity import ${entityClassName(ent, entityCollection(model))}
|
|
98
98
|
`)
|
|
99
99
|
})
|
|
100
100
|
}
|
|
@@ -47,7 +47,7 @@ dependencies = [
|
|
|
47
47
|
`)
|
|
48
48
|
|
|
49
49
|
const seen = new Set<string>()
|
|
50
|
-
for (const d of collectDeps(model, target.name, target.deps)) {
|
|
50
|
+
for (const d of collectDeps(model, target.name, target.deps, ctx$.log)) {
|
|
51
51
|
if (seen.has(d.name)) continue
|
|
52
52
|
seen.add(d.name)
|
|
53
53
|
const v = d.source === 'target' ? (d.version || '0.0') : d.version
|
|
@@ -70,7 +70,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
70
70
|
? `\n "apikey": env.get("${PROJECTNAME}_APIKEY"),`
|
|
71
71
|
: ''
|
|
72
72
|
|
|
73
|
-
const opnames = Object.keys(entity.op)
|
|
73
|
+
const opnames = Object.keys(entity.op || {})
|
|
74
74
|
const hasLoad = opnames.includes('load')
|
|
75
75
|
const hasList = opnames.includes('list')
|
|
76
76
|
|
|
@@ -78,8 +78,8 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
78
78
|
return
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
const loadOp = entity.op
|
|
82
|
-
const listOp = entity.op
|
|
81
|
+
const loadOp = entity.op?.load
|
|
82
|
+
const listOp = entity.op?.list
|
|
83
83
|
|
|
84
84
|
const loadPoint = loadOp?.points?.[0]
|
|
85
85
|
const loadPath = loadPoint ? normalizePathParams(loadPoint.parts || [], loadPoint?.args?.params || [], loadPoint?.rename?.param) : ''
|
|
@@ -82,7 +82,7 @@ const TestEntity = cmp(function TestEntity(props: any) {
|
|
|
82
82
|
// it only applies to entities that actually declare a `list` op. Others
|
|
83
83
|
// (e.g. Batch = create/load) have no list endpoint — make_point would error
|
|
84
84
|
// and the stream would yield nothing — so skip the test for them.
|
|
85
|
-
const hasList = !!(entity.op && (entity.op as any)
|
|
85
|
+
const hasList = !!(entity.op && (entity.op as any)?.list)
|
|
86
86
|
|
|
87
87
|
File({ name: 'test_' + entity.name + '_entity.' + target.ext }, () => {
|
|
88
88
|
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
// $STRING -> String, $INTEGER -> Integer, $NUMBER -> Float, $BOOLEAN -> Boolean,
|
|
13
13
|
// $OBJECT -> Hash, $ARRAY -> Array, unknown -> Object.
|
|
14
14
|
//
|
|
15
|
-
// Type-name scheme (
|
|
15
|
+
// Type-name scheme (as TS, with one Ruby-only guard): data type = <Name>,
|
|
16
|
+
// except where Ruby core already owns that constant — `File`, `Time`, `Data`,
|
|
17
|
+
// … — which would be silently REPLACED by the assignment; those become
|
|
18
|
+
// <Name>Type (see rbSafeTypeName). Per-op request
|
|
16
19
|
// <Name>LoadMatch / <Name>ListMatch / <Name>RemoveMatch (query/id ops),
|
|
17
20
|
// <Name>CreateData / <Name>UpdateData (body ops). An op WITH params -> a Struct of
|
|
18
21
|
// those params (reqd:false -> annotated `[Type, nil]`). An op WITHOUT params -> a
|
|
@@ -27,7 +30,7 @@ import {
|
|
|
27
30
|
File, Content,
|
|
28
31
|
} from '@voxgig/sdkgen'
|
|
29
32
|
|
|
30
|
-
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions } from '@voxgig/sdkgen'
|
|
33
|
+
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames, rbSafeTypeName } from '@voxgig/sdkgen'
|
|
31
34
|
|
|
32
35
|
import {
|
|
33
36
|
KIT,
|
|
@@ -89,11 +92,10 @@ const EntityTypes = cmp(function EntityTypes(props: any) {
|
|
|
89
92
|
// filter, so inactive entities still get class files referencing these
|
|
90
93
|
// typed names. Filter on `name` (always present), NOT `active` — parity
|
|
91
94
|
// with the go emitter's fix.
|
|
92
|
-
const entityList =
|
|
95
|
+
const entityList = deriveEntityNames(entity)
|
|
93
96
|
// Derive the PascalCase Name up-front — it is set LAZILY by names(), so an
|
|
94
97
|
// entity not yet named (e.g. a fieldless placeholder) would otherwise read
|
|
95
98
|
// `Name = undefined` below. Parity with the go emitter's fix.
|
|
96
|
-
entityList.forEach((e: any) => { if (null == e.Name) names(e, e.name) })
|
|
97
99
|
|
|
98
100
|
// Surface duplicate generated type names (two entities with the same
|
|
99
101
|
// PascalCase Name) — they would redeclare a type in statically-typed
|
|
@@ -116,12 +118,20 @@ const EntityTypes = cmp(function EntityTypes(props: any) {
|
|
|
116
118
|
|
|
117
119
|
entityList.forEach((ent: any) => {
|
|
118
120
|
const Name = ent.Name
|
|
121
|
+
// Ruby constants share ONE namespace with the core classes, and
|
|
122
|
+
// assigning one silently replaces it — an entity named `File` emitting
|
|
123
|
+
// `File = Struct.new(...)` clobbers ::File and every later `File.join`
|
|
124
|
+
// raises NoMethodError. Only the bare data-type constant needs the
|
|
125
|
+
// guard; the per-op names below always carry a suffix that no core
|
|
126
|
+
// constant matches. The `client.File(...)` accessor is a METHOD, a
|
|
127
|
+
// separate namespace, so the public surface is unchanged.
|
|
128
|
+
const TypeName = rbSafeTypeName(Name)
|
|
119
129
|
const fields = (ent.fields ? each(ent.fields) : [])
|
|
120
130
|
.filter((f: any) => f.active !== false)
|
|
121
131
|
|
|
122
132
|
// Entity data model: one member per field (`req:false` -> nilable).
|
|
123
133
|
emitStruct(
|
|
124
|
-
|
|
134
|
+
TypeName,
|
|
125
135
|
`${Name} entity data model.`,
|
|
126
136
|
fields.map((f: any) => ({ name: f.name, type: f.type, optional: false === f.req })),
|
|
127
137
|
)
|
|
@@ -4,7 +4,7 @@ import * as Path from 'node:path'
|
|
|
4
4
|
import {
|
|
5
5
|
cmp, each, camelify, names,
|
|
6
6
|
File, Content, Folder, Fragment, Line, FeatureHook, Slot,
|
|
7
|
-
entityClassName,
|
|
7
|
+
entityClassName, entityCollection,
|
|
8
8
|
} from '@voxgig/sdkgen'
|
|
9
9
|
|
|
10
10
|
import {
|
|
@@ -22,7 +22,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
22
22
|
// Collision-free entity CLASS name (see entityClassName): normally
|
|
23
23
|
// `<Name>Entity`, disambiguated when it would clash with another entity's
|
|
24
24
|
// data-type name. The snake-cased source-file name is unaffected.
|
|
25
|
-
const entityColl =
|
|
25
|
+
const entityColl = entityCollection(model)
|
|
26
26
|
const cls = entityClassName(entity, entityColl)
|
|
27
27
|
|
|
28
28
|
const entrep = {
|
|
@@ -38,7 +38,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
38
38
|
|
|
39
39
|
File({ name: entity.name + '_entity.' + target.ext }, () => {
|
|
40
40
|
|
|
41
|
-
const opnames = Object.keys(entity.op)
|
|
41
|
+
const opnames = Object.keys(entity.op || {})
|
|
42
42
|
|
|
43
43
|
const opfrags =
|
|
44
44
|
(['load', 'list', 'create', 'update', 'remove']
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
import { cmp, Content, entityClassName } from '@voxgig/sdkgen'
|
|
3
|
+
import { cmp, Content, entityClassName, entityCollection } from '@voxgig/sdkgen'
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
KIT,
|
|
@@ -14,7 +14,7 @@ const MainEntity = cmp(async function MainEntity(props: any) {
|
|
|
14
14
|
|
|
15
15
|
// Return the collision-free class (entityClassName); the accessor METHOD name
|
|
16
16
|
// (entity.Name) is unchanged so callers still write client.<Name>.
|
|
17
|
-
const cls = entityClassName(entity,
|
|
17
|
+
const cls = entityClassName(entity, entityCollection(model))
|
|
18
18
|
|
|
19
19
|
Content(`
|
|
20
20
|
# Canonical facade: client.${entity.Name}.list / client.${entity.Name}.load({ "id" => ... })
|
|
@@ -39,7 +39,7 @@ gemspec
|
|
|
39
39
|
|
|
40
40
|
`)
|
|
41
41
|
|
|
42
|
-
for (const d of collectDeps(model, target.name, target.deps)) {
|
|
42
|
+
for (const d of collectDeps(model, target.name, target.deps, ctx$.log)) {
|
|
43
43
|
Content(`gem "${d.name}", "~> ${versionOf(d)}"
|
|
44
44
|
`)
|
|
45
45
|
}
|
|
@@ -51,7 +51,7 @@ gemspec
|
|
|
51
51
|
// twice (Gem::InvalidSpecificationException at `gem build`), so the
|
|
52
52
|
// unconstrained json fallback is only emitted when the model's own
|
|
53
53
|
// dependency list doesn't already declare json.
|
|
54
|
-
const deps = collectDeps(model, target.name, target.deps)
|
|
54
|
+
const deps = collectDeps(model, target.name, target.deps, ctx$.log)
|
|
55
55
|
const hasJson = deps.some((d: any) => 'json' === d.name)
|
|
56
56
|
|
|
57
57
|
Content(`Gem::Specification.new do |spec|
|
|
@@ -70,7 +70,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
70
70
|
? `\n "apikey" => env["${PROJECTNAME}_APIKEY"],`
|
|
71
71
|
: ''
|
|
72
72
|
|
|
73
|
-
const opnames = Object.keys(entity.op)
|
|
73
|
+
const opnames = Object.keys(entity.op || {})
|
|
74
74
|
const hasLoad = opnames.includes('load')
|
|
75
75
|
const hasList = opnames.includes('list')
|
|
76
76
|
|
|
@@ -78,8 +78,8 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
78
78
|
return
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
const loadOp = entity.op
|
|
82
|
-
const listOp = entity.op
|
|
81
|
+
const loadOp = entity.op?.load
|
|
82
|
+
const listOp = entity.op?.list
|
|
83
83
|
|
|
84
84
|
const loadPoint = loadOp?.points?.[0]
|
|
85
85
|
const loadPath = loadPoint ? normalizePathParams(loadPoint.parts || [], loadPoint?.args?.params || [], loadPoint?.rename?.param) : ''
|
|
@@ -50,7 +50,7 @@ const TestEntity = cmp(function TestEntity(props: any) {
|
|
|
50
50
|
// it only applies to entities that declare a list op. Others (e.g. Batch =
|
|
51
51
|
// create/load) have no list endpoint — make_point errors and the stream
|
|
52
52
|
// yields nothing — so skip the stream test for them.
|
|
53
|
-
const hasList = !!(entity.op && (entity.op as any)
|
|
53
|
+
const hasList = !!(entity.op && (entity.op as any)?.list)
|
|
54
54
|
|
|
55
55
|
const basicflow: ModelEntityFlow | undefined =
|
|
56
56
|
getModelPath(model, `main.${KIT}.flow.Basic${nom(entity, 'Name')}Flow`)
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
Folder,
|
|
6
6
|
cmp,
|
|
7
7
|
each,
|
|
8
|
-
entityClassName,
|
|
8
|
+
entityClassName, entityCollection,
|
|
9
9
|
} from '@voxgig/sdkgen'
|
|
10
10
|
|
|
11
11
|
|
|
@@ -27,7 +27,7 @@ const EntityBase = cmp(async function EntityBase(props: any) {
|
|
|
27
27
|
const { model } = props.ctx$
|
|
28
28
|
|
|
29
29
|
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
30
|
-
const entityColl =
|
|
30
|
+
const entityColl = entityCollection(model)
|
|
31
31
|
|
|
32
32
|
Folder({ name: 'entity' }, () => {
|
|
33
33
|
File({ name: 'mod.' + target.ext }, () => {
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
// types yet (parity intent, not dead-code churn).
|
|
26
26
|
|
|
27
27
|
import {
|
|
28
|
-
cmp, each,
|
|
28
|
+
cmp, each,
|
|
29
29
|
File, Content, Folder,
|
|
30
30
|
} from '@voxgig/sdkgen'
|
|
31
31
|
|
|
32
|
-
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions } from '@voxgig/sdkgen'
|
|
32
|
+
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames } from '@voxgig/sdkgen'
|
|
33
33
|
|
|
34
34
|
import {
|
|
35
35
|
KIT,
|
|
@@ -85,8 +85,7 @@ const EntityTypes = cmp(function EntityTypes(props: any) {
|
|
|
85
85
|
// Emit for every entity that gets an entity file (filter on `name`, always
|
|
86
86
|
// present; derive `Name` here so the struct set is deterministic — parity
|
|
87
87
|
// with the go emitter's fix).
|
|
88
|
-
const entityList =
|
|
89
|
-
entityList.forEach((e: any) => { if (null == e.Name) names(e, e.name) })
|
|
88
|
+
const entityList = deriveEntityNames(entity)
|
|
90
89
|
|
|
91
90
|
// Surface duplicate generated type names (two entities with the same
|
|
92
91
|
// PascalCase Name) — they would redeclare a type in statically-typed
|
|
@@ -4,7 +4,7 @@ import * as Path from 'node:path'
|
|
|
4
4
|
import {
|
|
5
5
|
cmp, camelify,
|
|
6
6
|
File, Content, Folder, Fragment,
|
|
7
|
-
entityClassName,
|
|
7
|
+
entityClassName, entityCollection,
|
|
8
8
|
} from '@voxgig/sdkgen'
|
|
9
9
|
|
|
10
10
|
import {
|
|
@@ -23,7 +23,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
23
23
|
// Collision-free entity CLASS name (see entityClassName): normally
|
|
24
24
|
// `<Name>Entity`, but disambiguated when it would clash with another
|
|
25
25
|
// entity's data-type name.
|
|
26
|
-
const entityColl =
|
|
26
|
+
const entityColl = entityCollection(model)
|
|
27
27
|
const cls = entityClassName(entity, entityColl)
|
|
28
28
|
|
|
29
29
|
const entrep = {
|
|
@@ -37,7 +37,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
37
37
|
|
|
38
38
|
File({ name: rustVarName(entity.name) + '.' + target.ext }, () => {
|
|
39
39
|
|
|
40
|
-
const opnames = Object.keys(entity.op)
|
|
40
|
+
const opnames = Object.keys(entity.op || {})
|
|
41
41
|
|
|
42
42
|
// For each CRUD op: if the spec defines it, splice in the real
|
|
43
43
|
// implementation. Otherwise emit a stub that satisfies the static
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
import { cmp, Content, entityClassName } from '@voxgig/sdkgen'
|
|
3
|
+
import { cmp, Content, entityClassName, entityCollection } from '@voxgig/sdkgen'
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
KIT,
|
|
@@ -17,7 +17,7 @@ const MainEntity = cmp(async function MainEntity(props: any) {
|
|
|
17
17
|
const { entity } = props
|
|
18
18
|
const { model } = props.ctx$
|
|
19
19
|
|
|
20
|
-
const entityColl =
|
|
20
|
+
const entityColl = entityCollection(model)
|
|
21
21
|
const cls = entityClassName(entity, entityColl)
|
|
22
22
|
const method = rustVarName(entity.name)
|
|
23
23
|
const mod = rustVarName(entity.name)
|
|
@@ -43,7 +43,7 @@ path = "lib.rs"
|
|
|
43
43
|
|
|
44
44
|
const prod: Record<string, string> = {}
|
|
45
45
|
const dev: Record<string, string> = {}
|
|
46
|
-
for (const d of collectDeps(model, target.name, target.deps)) {
|
|
46
|
+
for (const d of collectDeps(model, target.name, target.deps, ctx$.log)) {
|
|
47
47
|
// Target-level deps default to '*' when version is absent; feature
|
|
48
48
|
// deps require an explicit version.
|
|
49
49
|
const version = d.source === 'target' ? (d.version || '*') : d.version
|
|
@@ -33,7 +33,10 @@ use std::fs;
|
|
|
33
33
|
use std::path::PathBuf;
|
|
34
34
|
|
|
35
35
|
// Extract the body of every \`\`\`rust ... \`\`\` fenced block from markdown.
|
|
36
|
-
|
|
36
|
+
// Returns the blocks plus a flag that is true when the scan reached EOF with a
|
|
37
|
+
// fence still open (an unterminated \`\`\`rust block) — the caller fails on it
|
|
38
|
+
// rather than silently dropping the malformed block.
|
|
39
|
+
fn extract_rust_blocks(md: &str) -> (Vec<String>, bool) {
|
|
37
40
|
let mut blocks: Vec<String> = Vec::new();
|
|
38
41
|
let mut in_block = false;
|
|
39
42
|
let mut cur: Vec<&str> = Vec::new();
|
|
@@ -53,14 +56,15 @@ fn extract_rust_blocks(md: &str) -> Vec<String> {
|
|
|
53
56
|
}
|
|
54
57
|
cur.push(line);
|
|
55
58
|
}
|
|
56
|
-
blocks
|
|
59
|
+
(blocks, in_block)
|
|
57
60
|
}
|
|
58
61
|
|
|
59
|
-
// Balanced (), [], {} outside of string literals
|
|
60
|
-
//
|
|
62
|
+
// Balanced (), [], {} outside of string literals, with each closer matching the
|
|
63
|
+
// most-recent opener (so "([)]" is rejected, not just counted). Naive quote
|
|
64
|
+
// toggle: the generated snippets never embed an escaped quote inside a string.
|
|
61
65
|
fn is_balanced(block: &str) -> bool {
|
|
62
66
|
let mut in_str = false;
|
|
63
|
-
let mut
|
|
67
|
+
let mut stack: Vec<char> = Vec::new();
|
|
64
68
|
for c in block.chars() {
|
|
65
69
|
if c == '"' {
|
|
66
70
|
in_str = !in_str;
|
|
@@ -70,17 +74,18 @@ fn is_balanced(block: &str) -> bool {
|
|
|
70
74
|
continue;
|
|
71
75
|
}
|
|
72
76
|
match c {
|
|
73
|
-
'('
|
|
77
|
+
'(' => stack.push(')'),
|
|
78
|
+
'[' => stack.push(']'),
|
|
79
|
+
'{' => stack.push('}'),
|
|
74
80
|
')' | ']' | '}' => {
|
|
75
|
-
|
|
76
|
-
if depth < 0 {
|
|
81
|
+
if stack.pop() != Some(c) {
|
|
77
82
|
return false;
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
85
|
_ => {}
|
|
81
86
|
}
|
|
82
87
|
}
|
|
83
|
-
|
|
88
|
+
stack.is_empty() && !in_str
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
#[test]
|
|
@@ -98,7 +103,14 @@ fn readme_rust_snippets_wellformed() {
|
|
|
98
103
|
Ok(s) => s,
|
|
99
104
|
Err(_) => continue, // doc not generated in this run — tolerate
|
|
100
105
|
};
|
|
101
|
-
let blocks = extract_rust_blocks(&src);
|
|
106
|
+
let (blocks, unterminated) = extract_rust_blocks(&src);
|
|
107
|
+
// A fence opened but never closed is a malformed doc — fail rather than
|
|
108
|
+
// silently skipping the unterminated block.
|
|
109
|
+
assert!(
|
|
110
|
+
!unterminated,
|
|
111
|
+
"{}: unterminated \`\`\`rust fence (block never closed)",
|
|
112
|
+
label
|
|
113
|
+
);
|
|
102
114
|
for (i, block) in blocks.iter().enumerate() {
|
|
103
115
|
assert!(
|
|
104
116
|
!block.trim().is_empty(),
|
|
@@ -73,7 +73,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
73
73
|
? `("apikey", getp(&env, "${PROJECTNAME}_APIKEY"))`
|
|
74
74
|
: ''
|
|
75
75
|
|
|
76
|
-
const opnames = Object.keys(entity.op)
|
|
76
|
+
const opnames = Object.keys(entity.op || {})
|
|
77
77
|
const hasLoad = opnames.includes('load')
|
|
78
78
|
const hasList = opnames.includes('list')
|
|
79
79
|
|
|
@@ -81,8 +81,8 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
81
81
|
return
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
const loadOp = (entity.op as any)
|
|
85
|
-
const listOp = (entity.op as any)
|
|
84
|
+
const loadOp = (entity.op as any)?.load
|
|
85
|
+
const listOp = (entity.op as any)?.list
|
|
86
86
|
|
|
87
87
|
// Load point info.
|
|
88
88
|
const loadPoint = loadOp?.points?.[0]
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
File, Content,
|
|
39
39
|
} from '@voxgig/sdkgen'
|
|
40
40
|
|
|
41
|
-
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions } from '@voxgig/sdkgen'
|
|
41
|
+
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames } from '@voxgig/sdkgen'
|
|
42
42
|
|
|
43
43
|
import {
|
|
44
44
|
KIT,
|
|
@@ -133,11 +133,10 @@ const EntityTypes = cmp(function EntityTypes(props: any) {
|
|
|
133
133
|
// filter, so inactive entities still get class files referencing these
|
|
134
134
|
// typed names. Filter on `name` (always present), NOT `active` — parity
|
|
135
135
|
// with the go emitter's fix.
|
|
136
|
-
const entityList =
|
|
136
|
+
const entityList = deriveEntityNames(entity)
|
|
137
137
|
// Derive the PascalCase Name up-front — it is set LAZILY by names(), so an
|
|
138
138
|
// entity not yet named (e.g. a fieldless placeholder) would otherwise read
|
|
139
139
|
// `Name = undefined` below. Parity with the go/py/java/csharp emitter's fix.
|
|
140
|
-
entityList.forEach((e: any) => { if (null == e.Name) names(e, e.name) })
|
|
141
140
|
|
|
142
141
|
// Surface duplicate generated type names (two entities with the same
|
|
143
142
|
// PascalCase Name) — they would redeclare a type in statically-typed
|
|
@@ -4,7 +4,7 @@ import * as Path from 'node:path'
|
|
|
4
4
|
import {
|
|
5
5
|
cmp, camelify, names,
|
|
6
6
|
File, Content, Folder, Fragment,
|
|
7
|
-
entityClassName,
|
|
7
|
+
entityClassName, entityCollection,
|
|
8
8
|
} from '@voxgig/sdkgen'
|
|
9
9
|
|
|
10
10
|
import {
|
|
@@ -23,7 +23,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
23
23
|
const scalapackage = scalaPackage(model)
|
|
24
24
|
|
|
25
25
|
// Collision-free entity CLASS name.
|
|
26
|
-
const entityColl =
|
|
26
|
+
const entityColl = entityCollection(model)
|
|
27
27
|
const cls = entityClassName(entity, entityColl)
|
|
28
28
|
|
|
29
29
|
const entrep = {
|
|
@@ -39,7 +39,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
39
39
|
|
|
40
40
|
File({ name: cls + '.' + target.ext }, () => {
|
|
41
41
|
|
|
42
|
-
const opnames = Object.keys(entity.op)
|
|
42
|
+
const opnames = Object.keys(entity.op || {})
|
|
43
43
|
|
|
44
44
|
// For each CRUD op: if the spec defines it, splice in the real
|
|
45
45
|
// implementation. Otherwise emit a stub that satisfies the SdkEntity
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
import { cmp, Content, entityClassName } from '@voxgig/sdkgen'
|
|
3
|
+
import { cmp, Content, entityClassName, entityCollection } from '@voxgig/sdkgen'
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
KIT,
|
|
@@ -18,7 +18,7 @@ const MainEntity = cmp(async function MainEntity(props: any) {
|
|
|
18
18
|
const { model } = props.ctx$
|
|
19
19
|
|
|
20
20
|
const scalapackage = scalaPackage(model)
|
|
21
|
-
const entityColl =
|
|
21
|
+
const entityColl = entityCollection(model)
|
|
22
22
|
const cls = entityClassName(entity, entityColl)
|
|
23
23
|
const accessor = scalaVarName(entity.name)
|
|
24
24
|
|
|
@@ -43,8 +43,11 @@ const ReadmeExamplesTest = cmp(function ReadmeExamplesTest(props: any) {
|
|
|
43
43
|
//
|
|
44
44
|
// Checks, PER DOCUMENT:
|
|
45
45
|
// 1. PRESENCE: the doc exists and holds at least one scala block.
|
|
46
|
-
// 2. STRUCTURE: every
|
|
47
|
-
//
|
|
46
|
+
// 2. STRUCTURE: every fence is closed (an odd number of triple-backtick
|
|
47
|
+
// markers means a fence was opened but never closed — the doc is truncated
|
|
48
|
+
// and split-based extraction would mis-segment the tail), AND every scala
|
|
49
|
+
// block's braces / parens / brackets balance, so a truncated or malformed
|
|
50
|
+
// generated snippet fails loudly.
|
|
48
51
|
//
|
|
49
52
|
// GENERATED by @voxgig/sdkgen — do not edit by hand.
|
|
50
53
|
|
|
@@ -85,6 +88,17 @@ object ReadmeExamplesTest {
|
|
|
85
88
|
private def readDoc(path: Path): String =
|
|
86
89
|
new String(Files.readAllBytes(path), "UTF-8")
|
|
87
90
|
|
|
91
|
+
// True when every triple-backtick fence in the document is paired. split(-1)
|
|
92
|
+
// yields (fenceCount + 1) parts, so an even fence count (all fences closed)
|
|
93
|
+
// gives an odd number of parts. An odd fence count means a fence was opened
|
|
94
|
+
// but never closed: the block-extraction above would then treat everything
|
|
95
|
+
// after it as one big "block", and a truncated snippet that happens to
|
|
96
|
+
// balance would pass silently. Detecting it here lets the gate fail loudly.
|
|
97
|
+
private def fencesClosed(text: String): Boolean = {
|
|
98
|
+
val fence = 96.toChar.toString.repeat(3)
|
|
99
|
+
text.split(java.util.regex.Pattern.quote(fence), -1).length % 2 == 1
|
|
100
|
+
}
|
|
101
|
+
|
|
88
102
|
// True when every open/close delimiter balances (ignores the subtlety of
|
|
89
103
|
// delimiters inside string literals — a generated snippet never nests an
|
|
90
104
|
// unbalanced delimiter in a string, and this catches truncation).
|
|
@@ -135,7 +149,12 @@ object ReadmeExamplesTest {
|
|
|
135
149
|
val label = ds(dj)(0)
|
|
136
150
|
val path = Paths.get(ds(dj)(1))
|
|
137
151
|
if (Files.exists(path)) {
|
|
138
|
-
val
|
|
152
|
+
val text = readDoc(path)
|
|
153
|
+
// A fence opened but never closed leaves an odd number of fence
|
|
154
|
+
// markers; fail loudly rather than trusting the mis-segmented tail.
|
|
155
|
+
if (!fencesClosed(text))
|
|
156
|
+
failures.add(label + " has an unclosed scala code fence")
|
|
157
|
+
val blocks = scalaBlocks(text)
|
|
139
158
|
var balancedCount = 0
|
|
140
159
|
var bi = 0
|
|
141
160
|
while (bi < blocks.size()) {
|
|
@@ -65,7 +65,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
65
65
|
const EntityName = nom(entity, 'Name')
|
|
66
66
|
const ENTLOWER = entity.name
|
|
67
67
|
|
|
68
|
-
const opnames = Object.keys(entity.op)
|
|
68
|
+
const opnames = Object.keys(entity.op || {})
|
|
69
69
|
const hasLoad = opnames.includes('load')
|
|
70
70
|
const hasList = opnames.includes('list')
|
|
71
71
|
|
|
@@ -73,8 +73,8 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
73
73
|
return
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
const loadOp = (entity.op as any)
|
|
77
|
-
const listOp = (entity.op as any)
|
|
76
|
+
const loadOp = (entity.op as any)?.load
|
|
77
|
+
const listOp = (entity.op as any)?.list
|
|
78
78
|
|
|
79
79
|
// Load point info.
|
|
80
80
|
const loadPoint = loadOp?.points?.[0]
|
|
@@ -40,7 +40,7 @@ const Test = cmp(function Test(props: any) {
|
|
|
40
40
|
getModelPath(model, `main.${KIT}.flow.Basic${EntityName}Flow`)
|
|
41
41
|
const hasEntity = null != basicflow && true === basicflow.active
|
|
42
42
|
|
|
43
|
-
const opnames = Object.keys(entity.op)
|
|
43
|
+
const opnames = Object.keys(entity.op || {})
|
|
44
44
|
const hasDirect = opnames.includes('load') || opnames.includes('list')
|
|
45
45
|
|
|
46
46
|
if (hasEntity) {
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
// the runtime's open shape.
|
|
22
22
|
|
|
23
23
|
import {
|
|
24
|
-
cmp, each,
|
|
24
|
+
cmp, each,
|
|
25
25
|
File, Content, Folder,
|
|
26
26
|
} from '@voxgig/sdkgen'
|
|
27
27
|
|
|
28
|
-
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions } from '@voxgig/sdkgen'
|
|
28
|
+
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames } from '@voxgig/sdkgen'
|
|
29
29
|
|
|
30
30
|
import {
|
|
31
31
|
KIT,
|
|
@@ -81,8 +81,7 @@ const EntityTypes = cmp(function EntityTypes(props: any) {
|
|
|
81
81
|
// Emit for every entity that gets an entity file (filter on `name`, always
|
|
82
82
|
// present; derive `Name` here so the struct set is deterministic — parity
|
|
83
83
|
// with the rust/go emitter's fix).
|
|
84
|
-
const entityList =
|
|
85
|
-
entityList.forEach((e: any) => { if (null == e.Name) names(e, e.name) })
|
|
84
|
+
const entityList = deriveEntityNames(entity)
|
|
86
85
|
|
|
87
86
|
// Surface duplicate generated type names (two entities with the same
|
|
88
87
|
// PascalCase Name) — they would redeclare a type in statically-typed
|
|
@@ -4,7 +4,7 @@ import * as Path from 'node:path'
|
|
|
4
4
|
import {
|
|
5
5
|
cmp, camelify, names,
|
|
6
6
|
Content, File, Folder, Fragment,
|
|
7
|
-
entityClassName,
|
|
7
|
+
entityClassName, entityCollection,
|
|
8
8
|
} from '@voxgig/sdkgen'
|
|
9
9
|
|
|
10
10
|
import {
|
|
@@ -20,7 +20,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
20
20
|
const { target, entity } = props
|
|
21
21
|
|
|
22
22
|
// Collision-free entity CLASS name (see entityClassName).
|
|
23
|
-
const entityColl =
|
|
23
|
+
const entityColl = entityCollection(model)
|
|
24
24
|
const cls = entityClassName(entity, entityColl)
|
|
25
25
|
|
|
26
26
|
const entrep = {
|
|
@@ -38,7 +38,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
38
38
|
|
|
39
39
|
File({ name: cls + '.' + target.ext }, () => {
|
|
40
40
|
|
|
41
|
-
const opnames = Object.keys(entity.op)
|
|
41
|
+
const opnames = Object.keys(entity.op || {})
|
|
42
42
|
|
|
43
43
|
// For each CRUD op: if the spec defines it, splice in the real
|
|
44
44
|
// implementation (an override). Otherwise leave the base-class
|