@@ -1013,6 +1013,14 @@ function generateCode() {
10131013 }
10141014 }
10151015
1016+ // Helper function to detect if an enum is a bitflag enum
1017+ // Hardcoded list of bitflag enums
1018+ const bitflagEnums = new Set ( [ "WatchKind" ] ) ;
1019+
1020+ function isBitflagEnum ( enumeration : any ) : boolean {
1021+ return bitflagEnums . has ( enumeration . name ) ;
1022+ }
1023+
10161024 // Generate enumerations
10171025 writeLine ( "// Enumerations\n" ) ;
10181026
@@ -1041,6 +1049,8 @@ function generateCode() {
10411049
10421050 const enumValues = enumeration . values . map ( value => ( {
10431051 value : String ( value . value ) ,
1052+ numericValue : Number ( value . value ) ,
1053+ name : value . name ,
10441054 identifier : `${ enumeration . name } ${ value . name } ` ,
10451055 documentation : value . documentation ,
10461056 deprecated : value . deprecated ,
@@ -1066,6 +1076,194 @@ function generateCode() {
10661076
10671077 writeLine ( ")" ) ;
10681078 writeLine ( "" ) ;
1079+
1080+ // Generate String() method for non-string enums
1081+ if ( enumeration . type . name !== "string" ) {
1082+ const isBitflag = isBitflagEnum ( enumeration ) ;
1083+
1084+ if ( isBitflag ) {
1085+ // Generate bitflag-aware String() method using stringer-style efficiency
1086+ const sortedValues = [ ...enumValues ] . sort ( ( a , b ) => a . numericValue - b . numericValue ) ;
1087+ const names = sortedValues . map ( v => v . name ) ;
1088+ const values = sortedValues . map ( v => v . numericValue ) ;
1089+
1090+ const nameConst = `_$ { enumeration . name } _name `;
1091+ const indexVar = `_$ { enumeration . name } _index `;
1092+ const combinedNames = names . join ( "") ;
1093+
1094+ writeLine ( `const ${ nameConst } = "${ combinedNames } "` ) ;
1095+ write ( `var ${ indexVar } = [...]uint16{0` ) ;
1096+ let offset = 0 ;
1097+ for ( const name of names ) {
1098+ offset += name . length ;
1099+ write ( `, ${ offset } ` ) ;
1100+ }
1101+ writeLine ( `}` ) ;
1102+ writeLine ( "" ) ;
1103+
1104+ writeLine ( `func (e ${ enumeration . name } ) String() string {` ) ;
1105+ writeLine ( `\tif e == 0 {` ) ;
1106+ writeLine ( `\t\treturn "0"` ) ;
1107+ writeLine ( `\t}` ) ;
1108+ writeLine ( `\tvar parts []string` ) ;
1109+ for ( let i = 0 ; i < values . length ; i ++ ) {
1110+ writeLine ( `\tif e&${ values [ i ] } != 0 {` ) ;
1111+ writeLine ( `\t\tparts = append(parts, ${ nameConst } [${ indexVar } [${ i } ]:${ indexVar } [${ i + 1 } ]])` ) ;
1112+ writeLine ( `\t}` ) ;
1113+ }
1114+ writeLine ( `\tif len(parts) == 0 {` ) ;
1115+ writeLine ( `\t\treturn fmt.Sprintf("${ enumeration . name } (%d)", e)` ) ;
1116+ writeLine ( `\t}` ) ;
1117+ writeLine ( `\treturn strings.Join(parts, "|")` ) ;
1118+ writeLine ( `}` ) ;
1119+ writeLine ( "" ) ;
1120+ }
1121+ else {
1122+ // Generate regular String() method using stringer-style approach
1123+ // Split values into runs of contiguous values
1124+ const sortedValues = [ ...enumValues ] . sort ( ( a , b ) => a . numericValue - b . numericValue ) ;
1125+
1126+ // Split into runs
1127+ const runs : Array < { names : string [ ] ; values : number [ ] ; } > = [ ] ;
1128+ let currentRun = { names : [ sortedValues [ 0 ] . name ] , values : [ sortedValues [ 0 ] . numericValue ] } ;
1129+
1130+ for ( let i = 1 ; i < sortedValues . length ; i ++ ) {
1131+ if ( sortedValues [ i ] . numericValue === sortedValues [ i - 1 ] . numericValue + 1 ) {
1132+ currentRun . names . push ( sortedValues [ i ] . name ) ;
1133+ currentRun . values . push ( sortedValues [ i ] . numericValue ) ;
1134+ }
1135+ else {
1136+ runs . push ( currentRun ) ;
1137+ currentRun = { names : [ sortedValues [ i ] . name ] , values : [ sortedValues [ i ] . numericValue ] } ;
1138+ }
1139+ }
1140+ runs . push ( currentRun ) ;
1141+
1142+ const nameConst = `_${ enumeration . name } _name` ;
1143+ const indexVar = `_${ enumeration . name } _index` ;
1144+
1145+ if ( runs . length === 1 ) {
1146+ // Single contiguous run - simple case
1147+ const combinedNames = runs [ 0 ] . names . join ( "" ) ;
1148+ writeLine ( `const ${ nameConst } = "${ combinedNames } "` ) ;
1149+ write ( `var ${ indexVar } = [...]uint16{0` ) ;
1150+ let offset = 0 ;
1151+ for ( const name of runs [ 0 ] . names ) {
1152+ offset += name . length ;
1153+ write ( `, ${ offset } ` ) ;
1154+ }
1155+ writeLine ( `}` ) ;
1156+ writeLine ( "" ) ;
1157+
1158+ const minVal = runs [ 0 ] . values [ 0 ] ;
1159+ writeLine ( `func (e ${ enumeration . name } ) String() string {` ) ;
1160+ writeLine ( `\ti := int(e) - ${ minVal } ` ) ;
1161+ // For unsigned types, i can still be negative if e < minVal (due to underflow in conversion)
1162+ // So we always need to check both bounds
1163+ writeLine ( `\tif i < 0 || i >= len(${ indexVar } )-1 {` ) ;
1164+ writeLine ( `\t\treturn fmt.Sprintf("${ enumeration . name } (%d)", e)` ) ;
1165+ writeLine ( `\t}` ) ;
1166+ writeLine ( `\treturn ${ nameConst } [${ indexVar } [i]:${ indexVar } [i+1]]` ) ;
1167+ writeLine ( `}` ) ;
1168+ writeLine ( "" ) ;
1169+ }
1170+ else if ( runs . length <= 10 ) {
1171+ // Multiple runs - use switch statement
1172+ let allNames = "" ;
1173+ const runInfo : Array < { startOffset : number ; endOffset : number ; minVal : number ; maxVal : number ; } > = [ ] ;
1174+
1175+ for ( const run of runs ) {
1176+ const startOffset = allNames . length ;
1177+ allNames += run . names . join ( "" ) ;
1178+ const endOffset = allNames . length ;
1179+ runInfo . push ( {
1180+ startOffset,
1181+ endOffset,
1182+ minVal : run . values [ 0 ] ,
1183+ maxVal : run . values [ run . values . length - 1 ] ,
1184+ } ) ;
1185+ }
1186+
1187+ writeLine ( `const ${ nameConst } = "${ allNames } "` ) ;
1188+ writeLine ( "" ) ;
1189+
1190+ // Generate index variables for each run
1191+ for ( let i = 0 ; i < runs . length ; i ++ ) {
1192+ write ( `var ${ indexVar } _${ i } = [...]uint16{0` ) ;
1193+ let offset = 0 ;
1194+ for ( const name of runs [ i ] . names ) {
1195+ offset += name . length ;
1196+ write ( `, ${ offset } ` ) ;
1197+ }
1198+ writeLine ( `}` ) ;
1199+ }
1200+ writeLine ( "" ) ;
1201+
1202+ writeLine ( `func (e ${ enumeration . name } ) String() string {` ) ;
1203+ writeLine ( `\tswitch {` ) ;
1204+
1205+ for ( let i = 0 ; i < runs . length ; i ++ ) {
1206+ const run = runs [ i ] ;
1207+ const info = runInfo [ i ] ;
1208+
1209+ if ( run . values . length === 1 ) {
1210+ writeLine ( `\tcase e == ${ run . values [ 0 ] } :` ) ;
1211+ writeLine ( `\t\treturn ${ nameConst } [${ info . startOffset } :${ info . endOffset } ]` ) ;
1212+ }
1213+ else {
1214+ if ( info . minVal === 0 && baseType . startsWith ( "uint" ) ) {
1215+ writeLine ( `\tcase e <= ${ info . maxVal } :` ) ;
1216+ }
1217+ else if ( info . minVal === 0 ) {
1218+ writeLine ( `\tcase 0 <= e && e <= ${ info . maxVal } :` ) ;
1219+ }
1220+ else {
1221+ writeLine ( `\tcase ${ info . minVal } <= e && e <= ${ info . maxVal } :` ) ;
1222+ }
1223+ writeLine ( `\t\ti := int(e) - ${ info . minVal } ` ) ;
1224+ writeLine ( `\t\treturn ${ nameConst } [${ info . startOffset } +${ indexVar } _${ i } [i]:${ info . startOffset } +${ indexVar } _${ i } [i+1]]` ) ;
1225+ }
1226+ }
1227+
1228+ writeLine ( `\tdefault:` ) ;
1229+ writeLine ( `\t\treturn fmt.Sprintf("${ enumeration . name } (%d)", e)` ) ;
1230+ writeLine ( `\t}` ) ;
1231+ writeLine ( `}` ) ;
1232+ writeLine ( "" ) ;
1233+ }
1234+ else {
1235+ // Too many runs - use a map
1236+ let allNames = "";
1237+ const valueMap : Array < { value : number ; startOffset : number ; endOffset : number ; } > = [ ] ;
1238+
1239+ for ( const run of runs ) {
1240+ for ( let i = 0 ; i < run . names . length ; i ++ ) {
1241+ const startOffset = allNames . length ;
1242+ allNames += run . names [ i ] ;
1243+ const endOffset = allNames . length ;
1244+ valueMap . push ( { value : run . values [ i ] , startOffset, endOffset } ) ;
1245+ }
1246+ }
1247+
1248+ writeLine ( `const ${ nameConst } = "${ allNames } "` ) ;
1249+ writeLine ( "" ) ;
1250+ writeLine ( `var ${ enumeration . name } _map = map[${ enumeration . name } ]string{` ) ;
1251+ for ( const entry of valueMap ) {
1252+ writeLine ( `\t${ entry . value } : ${ nameConst } [${ entry . startOffset } :${ entry . endOffset } ],` ) ;
1253+ }
1254+ writeLine ( `}` ) ;
1255+ writeLine ( "" ) ;
1256+
1257+ writeLine ( `func (e ${ enumeration . name } ) String() string {` ) ;
1258+ writeLine ( `\tif str, ok := ${ enumeration . name } _map[e]; ok {` ) ;
1259+ writeLine ( `\t\treturn str` ) ;
1260+ writeLine ( `\t}` ) ;
1261+ writeLine ( `\treturn fmt.Sprintf("${ enumeration . name } (%d)", e)` ) ;
1262+ writeLine ( `}` ) ;
1263+ writeLine ( "" ) ;
1264+ }
1265+ }
1266+ }
10691267 }
10701268
10711269 const requestsAndNotifications : ( Request | Notification ) [ ] = [ ...model . requests , ...model . notifications ] ;
0 commit comments