mirror of
https://github.com/navidrome/navidrome.git
synced 2026-05-03 06:51:16 +00:00
feat(plugins): implement XTP JSONSchema validation for generated schemas
Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
parent
e3bfcff8c4
commit
ad9cda9d57
2
.gitignore
vendored
2
.gitignore
vendored
@ -26,7 +26,7 @@ docker-compose.yml
|
||||
!contrib/docker-compose.yml
|
||||
binaries
|
||||
navidrome-*
|
||||
ndpgen
|
||||
/ndpgen
|
||||
AGENTS.md
|
||||
.github/prompts
|
||||
.github/instructions
|
||||
|
||||
5
Makefile
5
Makefile
@ -105,6 +105,11 @@ wire: check_go_env ##@Development Update Dependency Injection
|
||||
|
||||
gen: check_go_env ##@Development Run go generate for code generation
|
||||
go generate ./...
|
||||
cd plugins/cmd/ndpgen && go run . -host-wrappers -input=../../host -package=host
|
||||
cd plugins/cmd/ndpgen && go run . -input=../../host -output=../../pdk -go -python -rust
|
||||
cd plugins/cmd/ndpgen && go run . -capability-only -input=../../capabilities -output=../../pdk -go -rust
|
||||
cd plugins/cmd/ndpgen && go run . -schemas -input=../../capabilities
|
||||
go mod tidy -C plugins/pdk/go
|
||||
.PHONY: gen
|
||||
|
||||
snapshots: ##@Development Update (GoLang) Snapshot tests
|
||||
|
||||
@ -53,7 +53,4 @@
|
||||
// }
|
||||
//
|
||||
// func Register(impl Scrobbler) { ... }
|
||||
//
|
||||
//go:generate go run ../cmd/ndpgen -capability-only -input=. -output=../pdk -go -rust
|
||||
//go:generate go run ../cmd/ndpgen -schemas -input=.
|
||||
package capabilities
|
||||
|
||||
@ -68,7 +68,6 @@ components:
|
||||
schemas:
|
||||
AlbumImagesResponse:
|
||||
description: AlbumImagesResponse is the response for GetAlbumImages.
|
||||
type: object
|
||||
properties:
|
||||
images:
|
||||
type: array
|
||||
@ -79,7 +78,6 @@ components:
|
||||
- images
|
||||
AlbumInfoResponse:
|
||||
description: AlbumInfoResponse is the response for GetAlbumInfo.
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
@ -100,7 +98,6 @@ components:
|
||||
- url
|
||||
AlbumRequest:
|
||||
description: AlbumRequest is the common request for album-related functions.
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
@ -116,7 +113,6 @@ components:
|
||||
- artist
|
||||
ArtistBiographyResponse:
|
||||
description: ArtistBiographyResponse is the response for GetArtistBiography.
|
||||
type: object
|
||||
properties:
|
||||
biography:
|
||||
type: string
|
||||
@ -125,7 +121,6 @@ components:
|
||||
- biography
|
||||
ArtistImagesResponse:
|
||||
description: ArtistImagesResponse is the response for GetArtistImages.
|
||||
type: object
|
||||
properties:
|
||||
images:
|
||||
type: array
|
||||
@ -136,7 +131,6 @@ components:
|
||||
- images
|
||||
ArtistMBIDRequest:
|
||||
description: ArtistMBIDRequest is the request for GetArtistMBID.
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
@ -149,7 +143,6 @@ components:
|
||||
- name
|
||||
ArtistMBIDResponse:
|
||||
description: ArtistMBIDResponse is the response for GetArtistMBID.
|
||||
type: object
|
||||
properties:
|
||||
mbid:
|
||||
type: string
|
||||
@ -158,7 +151,6 @@ components:
|
||||
- mbid
|
||||
ArtistRef:
|
||||
description: ArtistRef is a reference to an artist with name and optional MBID.
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
@ -170,7 +162,6 @@ components:
|
||||
- name
|
||||
ArtistRequest:
|
||||
description: ArtistRequest is the common request for artist-related functions.
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
@ -186,7 +177,6 @@ components:
|
||||
- name
|
||||
ArtistURLResponse:
|
||||
description: ArtistURLResponse is the response for GetArtistURL.
|
||||
type: object
|
||||
properties:
|
||||
url:
|
||||
type: string
|
||||
@ -195,7 +185,6 @@ components:
|
||||
- url
|
||||
ImageInfo:
|
||||
description: ImageInfo represents an image with URL and size.
|
||||
type: object
|
||||
properties:
|
||||
url:
|
||||
type: string
|
||||
@ -209,7 +198,6 @@ components:
|
||||
- size
|
||||
SimilarArtistsRequest:
|
||||
description: SimilarArtistsRequest is the request for GetSimilarArtists.
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
@ -230,7 +218,6 @@ components:
|
||||
- limit
|
||||
SimilarArtistsResponse:
|
||||
description: SimilarArtistsResponse is the response for GetSimilarArtists.
|
||||
type: object
|
||||
properties:
|
||||
artists:
|
||||
type: array
|
||||
@ -241,7 +228,6 @@ components:
|
||||
- artists
|
||||
SongRef:
|
||||
description: SongRef is a reference to a song with name and optional MBID.
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
@ -253,7 +239,6 @@ components:
|
||||
- name
|
||||
TopSongsRequest:
|
||||
description: TopSongsRequest is the request for GetArtistTopSongs.
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
@ -274,7 +259,6 @@ components:
|
||||
- count
|
||||
TopSongsResponse:
|
||||
description: TopSongsResponse is the response for GetArtistTopSongs.
|
||||
type: object
|
||||
properties:
|
||||
songs:
|
||||
type: array
|
||||
|
||||
@ -11,7 +11,6 @@ components:
|
||||
schemas:
|
||||
SchedulerCallbackRequest:
|
||||
description: SchedulerCallbackRequest is the request provided when a scheduled task fires.
|
||||
type: object
|
||||
properties:
|
||||
scheduleId:
|
||||
type: string
|
||||
|
||||
@ -22,7 +22,6 @@ components:
|
||||
schemas:
|
||||
IsAuthorizedRequest:
|
||||
description: IsAuthorizedRequest is the request for authorization check.
|
||||
type: object
|
||||
properties:
|
||||
userId:
|
||||
type: string
|
||||
@ -35,7 +34,6 @@ components:
|
||||
- username
|
||||
NowPlayingRequest:
|
||||
description: NowPlayingRequest is the request for now playing notification.
|
||||
type: object
|
||||
properties:
|
||||
userId:
|
||||
type: string
|
||||
@ -57,7 +55,6 @@ components:
|
||||
- position
|
||||
ScrobbleRequest:
|
||||
description: ScrobbleRequest is the request for submitting a scrobble.
|
||||
type: object
|
||||
properties:
|
||||
userId:
|
||||
type: string
|
||||
@ -79,7 +76,6 @@ components:
|
||||
- timestamp
|
||||
TrackInfo:
|
||||
description: TrackInfo contains track metadata for scrobbling.
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
|
||||
@ -24,7 +24,6 @@ components:
|
||||
schemas:
|
||||
OnBinaryMessageRequest:
|
||||
description: OnBinaryMessageRequest is the request provided when a binary message is received.
|
||||
type: object
|
||||
properties:
|
||||
connectionId:
|
||||
type: string
|
||||
@ -37,7 +36,6 @@ components:
|
||||
- data
|
||||
OnCloseRequest:
|
||||
description: OnCloseRequest is the request provided when a WebSocket connection is closed.
|
||||
type: object
|
||||
properties:
|
||||
connectionId:
|
||||
type: string
|
||||
@ -57,7 +55,6 @@ components:
|
||||
- reason
|
||||
OnErrorRequest:
|
||||
description: OnErrorRequest is the request provided when an error occurs on a WebSocket connection.
|
||||
type: object
|
||||
properties:
|
||||
connectionId:
|
||||
type: string
|
||||
@ -70,7 +67,6 @@ components:
|
||||
- error
|
||||
OnTextMessageRequest:
|
||||
description: OnTextMessageRequest is the request provided when a text message is received.
|
||||
type: object
|
||||
properties:
|
||||
connectionId:
|
||||
type: string
|
||||
|
||||
23
plugins/cmd/ndpgen/go.mod
Normal file
23
plugins/cmd/ndpgen/go.mod
Normal file
@ -0,0 +1,23 @@
|
||||
module github.com/navidrome/navidrome/plugins/cmd/ndpgen
|
||||
|
||||
go 1.25
|
||||
|
||||
require (
|
||||
github.com/onsi/ginkgo/v2 v2.22.2
|
||||
github.com/onsi/gomega v1.36.2
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/tools v0.28.0 // indirect
|
||||
)
|
||||
42
plugins/cmd/ndpgen/go.sum
Normal file
42
plugins/cmd/ndpgen/go.sum
Normal file
@ -0,0 +1,42 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
|
||||
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
|
||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
||||
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@ -27,13 +27,13 @@ var _ = Describe("ndpgen CLI", Ordered, func() {
|
||||
)
|
||||
|
||||
BeforeAll(func() {
|
||||
// Set testdata directory
|
||||
testdataDir = filepath.Join(mustGetWd(GinkgoT()), "plugins", "cmd", "ndpgen", "testdata")
|
||||
// Set testdata directory (relative to ndpgen root)
|
||||
testdataDir = filepath.Join(mustGetWd(GinkgoT()), "testdata")
|
||||
|
||||
// Build the ndpgen binary
|
||||
ndpgenBin = filepath.Join(os.TempDir(), "ndpgen-test")
|
||||
cmd := exec.Command("go", "build", "-o", ndpgenBin, ".")
|
||||
cmd.Dir = filepath.Join(mustGetWd(GinkgoT()), "plugins", "cmd", "ndpgen")
|
||||
cmd.Dir = mustGetWd(GinkgoT())
|
||||
output, err := cmd.CombinedOutput()
|
||||
Expect(err).ToNot(HaveOccurred(), "Failed to build ndpgen: %s", output)
|
||||
DeferCleanup(func() {
|
||||
@ -512,13 +512,19 @@ func mustGetWd(t FullGinkgoTInterface) string {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Look for ndpgen's own go.mod (the subproject root)
|
||||
for {
|
||||
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
|
||||
return dir
|
||||
goModPath := filepath.Join(dir, "go.mod")
|
||||
if _, err := os.Stat(goModPath); err == nil {
|
||||
// Check if this is the ndpgen go.mod by reading it
|
||||
content, err := os.ReadFile(goModPath)
|
||||
if err == nil && strings.Contains(string(content), "plugins/cmd/ndpgen") {
|
||||
return dir
|
||||
}
|
||||
}
|
||||
parent := filepath.Dir(dir)
|
||||
if parent == dir {
|
||||
t.Fatal("could not find project root")
|
||||
t.Fatal("could not find ndpgen project root")
|
||||
}
|
||||
dir = parent
|
||||
}
|
||||
|
||||
@ -32,12 +32,10 @@ type (
|
||||
}
|
||||
|
||||
// xtpObjectSchema represents an object schema in XTP.
|
||||
// Note: The Type field is technically not valid per the XTP JSON Schema,
|
||||
// but is required as a workaround for XTP's code generator to properly
|
||||
// resolve type information (especially for empty structs).
|
||||
// Per the XTP JSON Schema, ObjectSchema has properties, required, and description
|
||||
// but NOT a type field.
|
||||
xtpObjectSchema struct {
|
||||
Description string `yaml:"description,omitempty"`
|
||||
Type string `yaml:"type"`
|
||||
Properties yaml.Node `yaml:"properties"`
|
||||
Required []string `yaml:"required,omitempty"`
|
||||
}
|
||||
@ -203,7 +201,6 @@ func addTypeAndDeps(typeName string, cap Capability, knownTypes map[string]bool,
|
||||
func buildObjectSchema(st StructDef, knownTypes map[string]bool) xtpObjectSchema {
|
||||
schema := xtpObjectSchema{
|
||||
Description: cleanDocForYAML(st.Doc),
|
||||
Type: "object", // Required workaround for XTP code generator
|
||||
Properties: yaml.Node{Kind: yaml.MappingNode},
|
||||
}
|
||||
|
||||
|
||||
549
plugins/cmd/ndpgen/internal/xtp_schema.json
Normal file
549
plugins/cmd/ndpgen/internal/xtp_schema.json
Normal file
@ -0,0 +1,549 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {
|
||||
"$ref": "#/$defs/XtpVersion"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"version"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"version": {
|
||||
"const": "v0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"exports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z_$][a-zA-Z0-9_$]*$"
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"const": "v0"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"exports"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"version": {
|
||||
"const": "v1-draft"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"version": {
|
||||
"$ref": "#/$defs/XtpVersion"
|
||||
},
|
||||
"exports": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z_$][a-zA-Z0-9_$]*$": {
|
||||
"$ref": "#/$defs/Export"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"imports": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z_$][a-zA-Z0-9_$]*$": {
|
||||
"$ref": "#/$defs/Import"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"components": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"schemas": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z_$][a-zA-Z0-9_$]*$": {
|
||||
"$ref": "#/$defs/Schema"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"schemas"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"exports"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"$defs": {
|
||||
"XtpVersion": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v0",
|
||||
"v1-draft"
|
||||
]
|
||||
},
|
||||
"Export": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"codeSamples": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/CodeSample"
|
||||
}
|
||||
},
|
||||
"input": {
|
||||
"$ref": "#/$defs/Parameter"
|
||||
},
|
||||
"output": {
|
||||
"$ref": "#/$defs/Parameter"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CodeSample": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"lang": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"typescript",
|
||||
"csharp",
|
||||
"zig",
|
||||
"rust",
|
||||
"go",
|
||||
"python",
|
||||
"c++"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lang",
|
||||
"source"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Import": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"input": {
|
||||
"$ref": "#/$defs/Parameter"
|
||||
},
|
||||
"output": {
|
||||
"$ref": "#/$defs/Parameter"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ObjectSchema"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/EnumSchema"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ObjectSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z_$][a-zA-Z0-9_$]*$": {
|
||||
"$ref": "#/$defs/Property"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"required": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"properties"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"EnumSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"enum": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z_$][a-zA-Z0-9_$]*$"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"enum"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Parameter": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ValueParameter"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/RefParameter"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/MapParameter"
|
||||
}
|
||||
]
|
||||
},
|
||||
"RefParameter": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"$ref": {
|
||||
"$ref": "#/$defs/SchemaReference"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"contentType": {
|
||||
"$ref": "#/$defs/ContentType"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"$ref",
|
||||
"contentType"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ValueParameter": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"contentType": {
|
||||
"$ref": "#/$defs/ContentType"
|
||||
},
|
||||
"type": {
|
||||
"$ref": "#/$defs/XtpType"
|
||||
},
|
||||
"format": {
|
||||
"$ref": "#/$defs/XtpFormat"
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"items": {
|
||||
"type": "object",
|
||||
"$ref": "#/$defs/ArrayItem"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"contentType"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MapParameter": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "object"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"additionalProperties": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/NonMapProperty"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": false
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"contentType": {
|
||||
"$ref": "#/$defs/ContentType"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"additionalProperties",
|
||||
"contentType"
|
||||
]
|
||||
},
|
||||
"NonMapProperty": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ValueProperty"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/RefProperty"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Property": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ValueProperty"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/RefProperty"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/MapProperty"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ValueProperty": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"$ref": "#/$defs/XtpType"
|
||||
},
|
||||
"format": {
|
||||
"$ref": "#/$defs/XtpFormat"
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"items": {
|
||||
"type": "object",
|
||||
"$ref": "#/$defs/ArrayItem"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MapProperty": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "object"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"additionalProperties": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/NonMapProperty"
|
||||
},
|
||||
{
|
||||
"not": {
|
||||
"type": "object",
|
||||
"required": ["description"]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"additionalProperties"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RefProperty": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"$ref": {
|
||||
"$ref": "#/$defs/SchemaReference"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"$ref"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ContentType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"application/json",
|
||||
"application/x-binary",
|
||||
"text/plain; charset=utf-8"
|
||||
]
|
||||
},
|
||||
"SchemaReference": {
|
||||
"type": "string",
|
||||
"pattern": "^#/components/schemas/[^/]+$"
|
||||
},
|
||||
"XtpType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"integer",
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"object",
|
||||
"array",
|
||||
"buffer"
|
||||
]
|
||||
},
|
||||
"XtpFormat": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"int32",
|
||||
"int64",
|
||||
"float",
|
||||
"double",
|
||||
"date-time",
|
||||
"byte"
|
||||
]
|
||||
},
|
||||
"ArrayItem": {
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ValueArrayItem"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/RefArrayItem"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/MapArrayItem"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ValueArrayItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"$ref": "#/$defs/XtpType"
|
||||
},
|
||||
"format": {
|
||||
"$ref": "#/$defs/XtpFormat"
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RefArrayItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"$ref": {
|
||||
"$ref": "#/$defs/SchemaReference"
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"$ref"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MapArrayItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "object"
|
||||
},
|
||||
"additionalProperties": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/NonMapProperty"
|
||||
},
|
||||
{
|
||||
"not": {
|
||||
"type": "object",
|
||||
"required": ["description"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"additionalProperties"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,6 +54,10 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
Expect(schema).NotTo(BeEmpty())
|
||||
})
|
||||
|
||||
It("should validate against XTP JSONSchema", func() {
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
})
|
||||
|
||||
It("should have correct version", func() {
|
||||
doc := parseSchema(schema)
|
||||
Expect(doc["version"]).To(Equal("v1-draft"))
|
||||
@ -80,7 +84,8 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
components := doc["components"].(map[string]any)
|
||||
schemas := components["schemas"].(map[string]any)
|
||||
input := schemas["TestInput"].(map[string]any)
|
||||
Expect(input["type"]).To(Equal("object")) // Workaround for XTP code generator
|
||||
// Per XTP spec, ObjectSchema does NOT have a type field - only properties, required, description
|
||||
Expect(input).NotTo(HaveKey("type"))
|
||||
props := input["properties"].(map[string]any)
|
||||
Expect(props).To(HaveKey("name"))
|
||||
Expect(props).To(HaveKey("count"))
|
||||
@ -128,6 +133,10 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should validate against XTP JSONSchema", func() {
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
})
|
||||
|
||||
It("should not mark required field as nullable", func() {
|
||||
doc := parseSchema(schema)
|
||||
components := doc["components"].(map[string]any)
|
||||
@ -202,6 +211,10 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should validate against XTP JSONSchema", func() {
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
})
|
||||
|
||||
It("should define enum type with correct values", func() {
|
||||
doc := parseSchema(schema)
|
||||
components := doc["components"].(map[string]any)
|
||||
@ -261,6 +274,10 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should validate against XTP JSONSchema", func() {
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
})
|
||||
|
||||
It("should define string array with primitive type", func() {
|
||||
doc := parseSchema(schema)
|
||||
components := doc["components"].(map[string]any)
|
||||
@ -324,6 +341,9 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Validate against XTP JSONSchema
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
doc := parseSchema(schema)
|
||||
components := doc["components"].(map[string]any)
|
||||
schemas := components["schemas"].(map[string]any)
|
||||
@ -395,7 +415,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
}
|
||||
|
||||
Context("export with primitive string output", func() {
|
||||
It("should use type instead of $ref", func() {
|
||||
It("should use type instead of $ref and validate against XTP JSONSchema", func() {
|
||||
capability := Capability{
|
||||
Name: "test",
|
||||
SourceFile: "test",
|
||||
@ -407,6 +427,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(schema).NotTo(BeEmpty())
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
doc := parseSchema(schema)
|
||||
exports := doc["exports"].(map[string]any)
|
||||
@ -419,7 +440,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
})
|
||||
|
||||
Context("export with primitive bool output", func() {
|
||||
It("should use boolean type", func() {
|
||||
It("should use boolean type and validate against XTP JSONSchema", func() {
|
||||
capability := Capability{
|
||||
Name: "test",
|
||||
SourceFile: "test",
|
||||
@ -430,6 +451,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
}
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
doc := parseSchema(schema)
|
||||
exports := doc["exports"].(map[string]any)
|
||||
@ -441,7 +463,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
})
|
||||
|
||||
Context("export with primitive int output", func() {
|
||||
It("should use integer type", func() {
|
||||
It("should use integer type and validate against XTP JSONSchema", func() {
|
||||
capability := Capability{
|
||||
Name: "test",
|
||||
SourceFile: "test",
|
||||
@ -452,6 +474,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
}
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
doc := parseSchema(schema)
|
||||
exports := doc["exports"].(map[string]any)
|
||||
@ -463,7 +486,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
})
|
||||
|
||||
Context("export with pointer to primitive output", func() {
|
||||
It("should strip pointer and use primitive type", func() {
|
||||
It("should strip pointer and use primitive type and validate against XTP JSONSchema", func() {
|
||||
capability := Capability{
|
||||
Name: "test",
|
||||
SourceFile: "test",
|
||||
@ -474,6 +497,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
}
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
doc := parseSchema(schema)
|
||||
exports := doc["exports"].(map[string]any)
|
||||
@ -485,7 +509,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
})
|
||||
|
||||
Context("export with struct output", func() {
|
||||
It("should still use $ref", func() {
|
||||
It("should still use $ref and validate against XTP JSONSchema", func() {
|
||||
capability := Capability{
|
||||
Name: "test",
|
||||
SourceFile: "test",
|
||||
@ -499,6 +523,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
}
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
doc := parseSchema(schema)
|
||||
exports := doc["exports"].(map[string]any)
|
||||
@ -539,6 +564,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
}
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
schemas := getSchemas(schema)
|
||||
Expect(schemas).To(HaveKey("UsedInput"))
|
||||
@ -561,6 +587,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
}
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
schemas := getSchemas(schema)
|
||||
Expect(schemas).To(HaveKey("Input"))
|
||||
@ -583,6 +610,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
}
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
schemas := getSchemas(schema)
|
||||
Expect(schemas).To(HaveKey("Input"))
|
||||
@ -605,6 +633,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
}
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
schemas := getSchemas(schema)
|
||||
Expect(schemas).To(HaveKey("Input"))
|
||||
@ -625,6 +654,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
}
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
schemas := getSchemas(schema)
|
||||
Expect(schemas).To(HaveKey("Input"))
|
||||
@ -672,6 +702,7 @@ var _ = Describe("XTP Schema Generation", func() {
|
||||
|
||||
schema, err := GenerateSchema(capability)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ValidateXTPSchema(schema)).To(Succeed())
|
||||
|
||||
doc := parseSchema(schema)
|
||||
components := doc["components"].(map[string]any)
|
||||
|
||||
51
plugins/cmd/ndpgen/internal/xtp_schema_validate.go
Normal file
51
plugins/cmd/ndpgen/internal/xtp_schema_validate.go
Normal file
@ -0,0 +1,51 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// XTP JSONSchema specification, from
|
||||
// https://raw.githubusercontent.com/dylibso/xtp-bindgen/5090518dd86ba5e734dc225a33066ecc0ed2e12d/plugin/schema.json
|
||||
//
|
||||
//go:embed xtp_schema.json
|
||||
var xtpSchemaJSON string
|
||||
|
||||
// ValidateXTPSchema validates that the generated schema conforms to the XTP JSONSchema specification.
|
||||
// Returns nil if valid, or an error with validation details if invalid.
|
||||
func ValidateXTPSchema(generatedSchema []byte) error {
|
||||
// Parse the YAML schema to JSON for validation
|
||||
var schemaDoc map[string]any
|
||||
if err := yaml.Unmarshal(generatedSchema, &schemaDoc); err != nil {
|
||||
return fmt.Errorf("failed to parse generated schema as YAML: %w", err)
|
||||
}
|
||||
|
||||
// Convert to JSON for the validator
|
||||
jsonBytes, err := json.Marshal(schemaDoc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert schema to JSON: %w", err)
|
||||
}
|
||||
|
||||
schemaLoader := gojsonschema.NewStringLoader(xtpSchemaJSON)
|
||||
documentLoader := gojsonschema.NewBytesLoader(jsonBytes)
|
||||
|
||||
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
|
||||
if err != nil {
|
||||
return fmt.Errorf("schema validation failed: %w", err)
|
||||
}
|
||||
|
||||
if !result.Valid() {
|
||||
var errs []string
|
||||
for _, desc := range result.Errors() {
|
||||
errs = append(errs, fmt.Sprintf("- %s", desc))
|
||||
}
|
||||
return fmt.Errorf("schema validation errors:\n%s", strings.Join(errs, "\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -792,6 +792,11 @@ func generateSchemaFile(cap internal.Capability, outputDir string, dryRun, verbo
|
||||
return fmt.Errorf("generating schema: %w", err)
|
||||
}
|
||||
|
||||
// Validate the generated schema against XTP JSONSchema spec
|
||||
if err := internal.ValidateXTPSchema(schema); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Warning: Schema validation for %s:\n%s\n", cap.Name, err)
|
||||
}
|
||||
|
||||
// Use the source file name: websocket_callback.go -> websocket_callback.yaml
|
||||
schemaFile := filepath.Join(outputDir, cap.SourceFile+".yaml")
|
||||
|
||||
|
||||
@ -36,8 +36,4 @@
|
||||
//
|
||||
// Generated files follow the pattern <servicename>_gen.go and include a header comment
|
||||
// indicating they should not be edited manually.
|
||||
//
|
||||
//go:generate go run ../cmd/ndpgen -host-wrappers -input=. -package=host
|
||||
//go:generate go run ../cmd/ndpgen -input=. -output=../pdk -go -python -rust
|
||||
//go:generate go mod tidy -C ../pdk/go
|
||||
package host
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user