1- #[ path = "../../parser/src/lib.rs" ]
2- mod parser;
3-
41pub mod package {
5- pub use super :: parser:: * ;
2+ use serde:: Serialize ;
3+ use tucana:: shared:: { DefinitionDataType , FlowType , RuntimeFunctionDefinition } ;
4+ use std:: io:: ErrorKind ;
5+ use std:: {
6+ fs:: { self , DirEntry } ,
7+ io:: Error ,
8+ path:: Path ,
9+ } ;
10+
11+ #[ derive( Serialize , Clone , Debug ) ]
12+ pub struct DefinitionError {
13+ pub definition : String ,
14+ pub definition_type : MetaType ,
15+ pub error : String ,
16+ }
17+
18+ #[ derive( Debug ) ]
19+ pub struct Parser {
20+ pub features : Vec < Feature > ,
21+ }
22+
23+ #[ derive( Serialize , Clone , Debug ) ]
24+ pub struct Feature {
25+ pub name : String ,
26+ pub data_types : Vec < DefinitionDataType > ,
27+ pub flow_types : Vec < FlowType > ,
28+ pub runtime_functions : Vec < RuntimeFunctionDefinition > ,
29+ pub errors : Vec < DefinitionError > ,
30+ }
31+
32+ impl Feature {
33+ fn new ( name : String ) -> Self {
34+ Feature {
35+ name,
36+ data_types : Vec :: new ( ) ,
37+ flow_types : Vec :: new ( ) ,
38+ runtime_functions : Vec :: new ( ) ,
39+ errors : Vec :: new ( ) ,
40+ }
41+ }
42+ }
43+
44+ impl Parser {
45+ pub fn from_path ( path : & str ) -> Option < Self > {
46+ let reader = Reader :: from_path ( path) ?;
47+
48+ Some ( Self :: from_reader ( reader) )
49+ }
50+
51+ pub fn from_reader ( reader : Reader ) -> Self {
52+ let mut features: Vec < Feature > = vec ! [ ] ;
53+
54+ for meta in & reader. meta {
55+ let feature = features. iter_mut ( ) . find ( |f| f. name == meta. name ) ;
56+
57+ if let Some ( existing) = feature {
58+ Parser :: append_meta ( existing, meta) ;
59+ } else {
60+ let mut new_feature = Feature :: new ( meta. name . clone ( ) ) ;
61+ Parser :: append_meta ( & mut new_feature, meta) ;
62+ features. push ( new_feature) ;
63+ }
64+ }
65+
66+ Parser { features }
67+ }
68+
69+ pub fn extract_identifier ( definition : & str , meta_type : MetaType ) -> String {
70+ let field_name = match meta_type {
71+ MetaType :: DataType | MetaType :: FlowType => "identifier" ,
72+ MetaType :: RuntimeFunction => "runtime_name" ,
73+ } ;
74+
75+ // Look for the field pattern: "field_name": "value" or "field_name":"value"
76+ if let Some ( start) = definition. find ( & format ! ( "\" {field_name}\" " ) ) {
77+ // Find the colon after the field name
78+ if let Some ( colon_pos) = definition[ start..] . find ( ':' ) {
79+ let after_colon = & definition[ start + colon_pos + 1 ..] ;
80+
81+ // Skip whitespace and find the opening quote
82+ let trimmed = after_colon. trim_start ( ) ;
83+ if let Some ( stripped) = trimmed. strip_prefix ( '"' ) {
84+ // Find the closing quote
85+ if let Some ( end_quote) = stripped. find ( '"' ) {
86+ return trimmed[ 1 ..end_quote + 1 ] . to_string ( ) ;
87+ }
88+ }
89+ }
90+ }
91+
92+ // Fallback: return the whole definition if identifier can't be extracted
93+ definition. to_string ( )
94+ }
95+
96+ fn append_meta ( feature : & mut Feature , meta : & Meta ) {
97+ let definition = meta. definition_string . as_str ( ) ;
98+ match meta. r#type {
99+ MetaType :: DataType => match serde_json:: from_str :: < DefinitionDataType > ( definition) {
100+ Ok ( data_type) => feature. data_types . push ( data_type) ,
101+ Err ( err) => feature. errors . push ( DefinitionError {
102+ definition : Parser :: extract_identifier ( definition, MetaType :: DataType ) ,
103+ definition_type : MetaType :: DataType ,
104+ error : err. to_string ( ) ,
105+ } ) ,
106+ } ,
107+ MetaType :: FlowType => match serde_json:: from_str :: < FlowType > ( definition) {
108+ Ok ( flow_type) => feature. flow_types . push ( flow_type) ,
109+ Err ( err) => feature. errors . push ( DefinitionError {
110+ definition : Parser :: extract_identifier ( definition, MetaType :: FlowType ) ,
111+ definition_type : MetaType :: FlowType ,
112+ error : err. to_string ( ) ,
113+ } ) ,
114+ } ,
115+ MetaType :: RuntimeFunction => {
116+ match serde_json:: from_str :: < RuntimeFunctionDefinition > ( definition) {
117+ Ok ( func) => feature. runtime_functions . push ( func) ,
118+ Err ( err) => feature. errors . push ( DefinitionError {
119+ definition : Parser :: extract_identifier (
120+ definition,
121+ MetaType :: RuntimeFunction ,
122+ ) ,
123+ definition_type : MetaType :: RuntimeFunction ,
124+ error : err. to_string ( ) ,
125+ } ) ,
126+ }
127+ }
128+ }
129+ }
130+ }
131+
132+
133+ #[ derive( Serialize , Debug , Clone , Copy ) ]
134+ pub enum MetaType {
135+ FlowType ,
136+ DataType ,
137+ RuntimeFunction ,
138+ }
139+
140+ impl std:: fmt:: Display for MetaType {
141+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
142+ match self {
143+ MetaType :: FlowType => write ! ( f, "FlowType" ) ,
144+ MetaType :: DataType => write ! ( f, "DataType" ) ,
145+ MetaType :: RuntimeFunction => write ! ( f, "RuntimeFunction" ) ,
146+ }
147+ }
148+ }
149+
150+ pub struct Reader {
151+ pub meta : Vec < Meta > ,
152+ }
153+
154+ #[ derive( Clone ) ]
155+ pub struct Meta {
156+ pub name : String ,
157+ pub r#type : MetaType ,
158+ pub definition_string : String ,
159+ pub path : String ,
160+ }
161+
162+ impl Meta {
163+ pub fn read_from_file < P > ( name : String , r#type : MetaType , file_path : P ) -> Result < Meta , Error >
164+ where
165+ P : AsRef < Path > ,
166+ {
167+ let path = match file_path. as_ref ( ) . to_str ( ) {
168+ Some ( path) => path,
169+ None => return Err ( Error :: new ( ErrorKind :: InvalidInput , "Invalid path" ) ) ,
170+ } ;
171+
172+ if !path. ends_with ( "json" ) {
173+ return Err ( Error :: new (
174+ ErrorKind :: InvalidInput ,
175+ format ! (
176+ "File {} does not end with .json" ,
177+ file_path. as_ref( ) . display( )
178+ ) ,
179+ ) ) ;
180+ }
181+
182+ let content = match fs:: read_to_string ( & file_path) {
183+ Ok ( content) => content,
184+ Err ( err) => {
185+ println ! ( "Error reading file: {err}" ) ;
186+ return Err ( err) ;
187+ }
188+ } ;
189+
190+ Ok ( Meta {
191+ name,
192+ r#type,
193+ definition_string : content,
194+ path : path. to_string ( ) ,
195+ } )
196+ }
197+ }
198+
199+ /// Reader
200+ ///
201+ /// Expecting the file system to look like:
202+ /// - <path>
203+ /// - <feature>
204+ /// - <flow_types>
205+ /// - <data_types>
206+ /// - <runtime_functions>
207+ /// - <feature>
208+ /// - <flow_types>
209+ /// - <data_types>
210+ /// - <runtime_functions>
211+ impl Reader {
212+ pub fn from_path ( path : & str ) -> Option < Reader > {
213+ let mut result: Vec < Meta > = vec ! [ ] ;
214+
215+ // Reading the path folder
216+ for feature_path in fs:: read_dir ( path) . unwrap ( ) {
217+ let feature_path_result = match feature_path {
218+ Ok ( path) => path,
219+ Err ( _) => continue ,
220+ } ;
221+
222+ let feature_name = match get_file_name ( & feature_path_result) {
223+ Some ( file_name) => file_name,
224+ None => continue ,
225+ } ;
226+
227+ // Reading the feature folder
228+ for type_path in fs:: read_dir ( feature_path_result. path ( ) ) . unwrap ( ) {
229+ let type_path_result = match type_path {
230+ Ok ( path) => path,
231+ Err ( _) => continue ,
232+ } ;
233+
234+ let meta_type = match get_file_name ( & type_path_result) {
235+ Some ( name) => match name. as_str ( ) {
236+ "flow_type" => MetaType :: FlowType ,
237+ "data_type" => MetaType :: DataType ,
238+ "runtime_definition" => MetaType :: RuntimeFunction ,
239+ _ => continue ,
240+ } ,
241+ None => continue ,
242+ } ;
243+
244+ // Reading the type folder
245+ for definition_path in fs:: read_dir ( type_path_result. path ( ) ) . unwrap ( ) {
246+ let definition_path_result = match definition_path {
247+ Ok ( path) => path,
248+ Err ( _) => continue ,
249+ } ;
250+
251+ if definition_path_result. file_type ( ) . unwrap ( ) . is_file ( ) {
252+ let meta = Meta :: read_from_file (
253+ feature_name. clone ( ) ,
254+ meta_type,
255+ definition_path_result. path ( ) ,
256+ ) ;
257+
258+ if let Ok ( meta_result) = meta {
259+ result. push ( meta_result) ;
260+ }
261+ } else {
262+ for sub_definition_path in
263+ fs:: read_dir ( definition_path_result. path ( ) ) . unwrap ( )
264+ {
265+ let sub_definition_path_result = match sub_definition_path {
266+ Ok ( path) => path,
267+ Err ( _) => continue ,
268+ } ;
269+
270+ let meta = Meta :: read_from_file (
271+ feature_name. clone ( ) ,
272+ meta_type,
273+ sub_definition_path_result. path ( ) ,
274+ ) ;
275+
276+ if let Ok ( meta_result) = meta {
277+ result. push ( meta_result) ;
278+ }
279+ }
280+ }
281+ }
282+ }
283+ }
284+
285+ Some ( Reader { meta : result } )
286+ }
287+ }
288+
289+ fn get_file_name ( entry : & DirEntry ) -> Option < String > {
290+ entry
291+ . file_name ( )
292+ . to_str ( )
293+ . map ( |file_name| file_name. to_string ( ) )
294+ }
295+
296+
6297}
0 commit comments