@@ -3,6 +3,9 @@ use std::fs;
33use anyhow:: { Context , Result } ;
44use chrono:: Utc ;
55use colored:: Colorize ;
6+ use serde_json:: Value ;
7+ use vespertide_config:: FileFormat ;
8+ use vespertide_core:: MigrationPlan ;
69use vespertide_planner:: plan_next_migration;
710
811use crate :: utils:: {
@@ -46,14 +49,11 @@ pub fn cmd_revision(message: String) -> Result<()> {
4649 ) ;
4750 let path = migrations_dir. join ( & filename) ;
4851
49- let text = match format {
50- vespertide_config:: FileFormat :: Json => {
51- serde_json:: to_string_pretty ( & plan) . context ( "serialize migration plan" ) ?
52- }
53- _ => serde_yaml:: to_string ( & plan) . context ( "serialize migration plan" ) ?,
54- } ;
55-
56- fs:: write ( & path, text) . with_context ( || format ! ( "write migration file: {}" , path. display( ) ) ) ?;
52+ let schema_url = schema_url_for ( format) ;
53+ match format {
54+ FileFormat :: Json => write_json_with_schema ( & path, & plan, & schema_url) ?,
55+ FileFormat :: Yaml | FileFormat :: Yml => write_yaml ( & path, & plan, & schema_url) ?,
56+ }
5757
5858 println ! (
5959 "{} {}" ,
@@ -77,6 +77,47 @@ pub fn cmd_revision(message: String) -> Result<()> {
7777 Ok ( ( ) )
7878}
7979
80+ fn schema_url_for ( format : FileFormat ) -> String {
81+ // If not set, default to public raw GitHub schema location.
82+ // Users can override via VESP_SCHEMA_BASE_URL.
83+ let base = std:: env:: var ( "VESP_SCHEMA_BASE_URL" ) . ok ( ) ;
84+ let base = base. as_deref ( ) . unwrap_or (
85+ "https://raw.githubusercontent.com/dev-five-git/vespertide/refs/heads/main/schemas" ,
86+ ) ;
87+ let base = base. trim_end_matches ( '/' ) ;
88+ match format {
89+ FileFormat :: Json => format ! ( "{}/migration.schema.json" , base) ,
90+ FileFormat :: Yaml | FileFormat :: Yml => format ! ( "{}/migration.schema.json" , base) ,
91+ }
92+ }
93+
94+ fn write_json_with_schema (
95+ path : & std:: path:: Path ,
96+ plan : & MigrationPlan ,
97+ schema_url : & str ,
98+ ) -> Result < ( ) > {
99+ let mut value = serde_json:: to_value ( plan) . context ( "serialize migration plan to json" ) ?;
100+ if let Value :: Object ( ref mut map) = value {
101+ map. insert ( "$schema" . to_string ( ) , Value :: String ( schema_url. to_string ( ) ) ) ;
102+ }
103+ let text = serde_json:: to_string_pretty ( & value) . context ( "stringify json with schema" ) ?;
104+ fs:: write ( path, text) . with_context ( || format ! ( "write file: {}" , path. display( ) ) ) ?;
105+ Ok ( ( ) )
106+ }
107+
108+ fn write_yaml ( path : & std:: path:: Path , plan : & MigrationPlan , schema_url : & str ) -> Result < ( ) > {
109+ let mut value = serde_yaml:: to_value ( plan) . context ( "serialize migration plan to yaml value" ) ?;
110+ if let serde_yaml:: Value :: Mapping ( ref mut map) = value {
111+ map. insert (
112+ serde_yaml:: Value :: String ( "$schema" . to_string ( ) ) ,
113+ serde_yaml:: Value :: String ( schema_url. to_string ( ) ) ,
114+ ) ;
115+ }
116+ let text = serde_yaml:: to_string ( & value) . context ( "serialize yaml with schema" ) ?;
117+ fs:: write ( path, text) . with_context ( || format ! ( "write file: {}" , path. display( ) ) ) ?;
118+ Ok ( ( ) )
119+ }
120+
80121#[ cfg( test) ]
81122mod tests {
82123 use super :: * ;
0 commit comments