@@ -1064,7 +1064,10 @@ Second level methods.`;
10641064 } ) ;
10651065
10661066 it ( 'should handle nested generics' , ( ) => {
1067- const result = safelySeparateTypeStringOn ( 'Map<string, Record<string | number>> | Array' , '|' ) ;
1067+ const result = safelySeparateTypeStringOn (
1068+ 'Map<string, Record<string | number>> | Array' ,
1069+ '|' ,
1070+ ) ;
10681071 expect ( result ) . toEqual ( [ 'Map<string, Record<string | number>>' , 'Array' ] ) ;
10691072 } ) ;
10701073
@@ -1162,5 +1165,291 @@ Second level methods.`;
11621165 expect ( typedKeys . keys [ 0 ] . key ) . toBe ( 'options' ) ;
11631166 // The nested structure is complex - just verify we got the top-level key
11641167 } ) ;
1168+
1169+ it ( 'should handle list items with invalid structure but nested list' , ( ) => {
1170+ const md = `
1171+ * Some description without proper format
1172+ * \`validKey\` String - Valid nested key
1173+ * \`anotherKey\` Number - Another valid key
1174+ ` ;
1175+ const tokens = getTokens ( md ) ;
1176+ const list = findNextList ( tokens ) ;
1177+ const typedKeys = convertListToTypedKeys ( list ! ) ;
1178+
1179+ expect ( typedKeys . keys ) . toHaveLength ( 2 ) ;
1180+ expect ( typedKeys . keys [ 0 ] . key ) . toBe ( 'validKey' ) ;
1181+ expect ( typedKeys . keys [ 1 ] . key ) . toBe ( 'anotherKey' ) ;
1182+ } ) ;
1183+ } ) ;
1184+
1185+ describe ( 'extractStringEnum' , ( ) => {
1186+ it ( 'should handle unexpected token at start' , ( ) => {
1187+ const result = extractStringEnum ( 'values includes @invalid' ) ;
1188+ expect ( result ) . toBeNull ( ) ;
1189+ } ) ;
1190+
1191+ it ( 'should throw on unexpected separator' , ( ) => {
1192+ expect ( ( ) => extractStringEnum ( 'values includes "foo" @ "bar"' ) ) . toThrow (
1193+ / U n e x p e c t e d s e p a r a t o r t o k e n / ,
1194+ ) ;
1195+ } ) ;
1196+
1197+ it ( 'should throw on unexpected token after quote close' , ( ) => {
1198+ expect ( ( ) => extractStringEnum ( 'values includes "foo"!' ) ) . toThrow (
1199+ / U n e x p e c t e d s e p a r a t o r t o k e n / ,
1200+ ) ;
1201+ } ) ;
1202+
1203+ it ( 'should throw on unclosed quote' , ( ) => {
1204+ expect ( ( ) => extractStringEnum ( 'values includes "foo' ) ) . toThrow (
1205+ / U n e x p e c t e d e a r l y t e r m i n a t i o n / ,
1206+ ) ;
1207+ } ) ;
1208+
1209+ it ( 'should return null if no values found' , ( ) => {
1210+ const result = extractStringEnum ( 'can be ' ) ;
1211+ expect ( result ) . toBeNull ( ) ;
1212+ } ) ;
1213+
1214+ it ( 'should handle strikethrough wrapped deprecated values' , ( ) => {
1215+ const result = extractStringEnum ( 'values includes "foo", ~"bar"~' ) ;
1216+ expect ( result ) . toHaveLength ( 2 ) ;
1217+ expect ( result ! [ 0 ] . value ) . toBe ( 'foo' ) ;
1218+ expect ( result ! [ 1 ] . value ) . toBe ( 'bar' ) ;
1219+ } ) ;
1220+
1221+ it ( 'should throw on mismatched wrapper unwrapping' , ( ) => {
1222+ expect ( ( ) => extractStringEnum ( 'values includes ~"foo"!' ) ) . toThrow (
1223+ / E x p e c t e d a n u n w r a p p i n g t o k e n t h a t m a t c h e d / ,
1224+ ) ;
1225+ } ) ;
1226+
1227+ it ( 'should handle terminating with period' , ( ) => {
1228+ const result = extractStringEnum ( 'can be "foo".' ) ;
1229+ expect ( result ) . toHaveLength ( 1 ) ;
1230+ expect ( result ! [ 0 ] . value ) . toBe ( 'foo' ) ;
1231+ } ) ;
1232+
1233+ it ( 'should handle terminating with semicolon' , ( ) => {
1234+ const result = extractStringEnum ( 'can be "foo";' ) ;
1235+ expect ( result ) . toHaveLength ( 1 ) ;
1236+ } ) ;
1237+
1238+ it ( 'should handle terminating with hyphen' , ( ) => {
1239+ const result = extractStringEnum ( 'can be "foo" -' ) ;
1240+ expect ( result ) . toHaveLength ( 1 ) ;
1241+ } ) ;
1242+
1243+ it ( 'should handle or an Object terminator' , ( ) => {
1244+ const result = extractStringEnum ( 'can be "foo", or an Object' ) ;
1245+ expect ( result ) . toHaveLength ( 1 ) ;
1246+ expect ( result ! [ 0 ] . value ) . toBe ( 'foo' ) ;
1247+ } ) ;
1248+
1249+ it ( 'should handle , or an Object terminator' , ( ) => {
1250+ const result = extractStringEnum ( 'can be "foo", or an Object' ) ;
1251+ expect ( result ) . toHaveLength ( 1 ) ;
1252+ } ) ;
1253+
1254+ it ( 'should handle suffixes to ignore like (Deprecated)' , ( ) => {
1255+ const result = extractStringEnum ( 'can be "foo" (Deprecated), "bar"' ) ;
1256+ expect ( result ) . toHaveLength ( 2 ) ;
1257+ expect ( result ! [ 0 ] . value ) . toBe ( 'foo' ) ;
1258+ expect ( result ! [ 1 ] . value ) . toBe ( 'bar' ) ;
1259+ } ) ;
1260+
1261+ it ( 'should gracefully terminate after comma when encountering unquoted text' , ( ) => {
1262+ const result = extractStringEnum ( 'can be "foo", then other stuff' ) ;
1263+ expect ( result ) . toHaveLength ( 1 ) ;
1264+ expect ( result ! [ 0 ] . value ) . toBe ( 'foo' ) ;
1265+ } ) ;
1266+ } ) ;
1267+
1268+ describe ( 'extractReturnType' , ( ) => {
1269+ it ( 'should return null return type when no Returns pattern found' , ( ) => {
1270+ const tokens = getTokens ( 'This is just a description without returns' ) ;
1271+ const result = extractReturnType ( tokens ) ;
1272+ expect ( result . parsedReturnType ) . toBeNull ( ) ;
1273+ expect ( result . parsedDescription ) . toBe ( 'This is just a description without returns' ) ;
1274+ } ) ;
1275+
1276+ it ( 'should return null return type when Returns keyword present but no backticks' , ( ) => {
1277+ const tokens = getTokens ( 'Returns something without backticks' ) ;
1278+ const result = extractReturnType ( tokens ) ;
1279+ expect ( result . parsedReturnType ) . toBeNull ( ) ;
1280+ expect ( result . parsedDescription ) . toBe ( 'Returns something without backticks' ) ;
1281+ } ) ;
1282+
1283+ it ( 'should handle returns with continuous sentence' , ( ) => {
1284+ const tokens = getTokens ( 'Returns `String` the value' ) ;
1285+ const result = extractReturnType ( tokens ) ;
1286+ expect ( result . parsedReturnType ) . not . toBeNull ( ) ;
1287+ expect ( result . parsedReturnType ! . type ) . toBe ( 'String' ) ;
1288+ expect ( result . parsedDescription ) . toBe ( 'the value' ) ;
1289+ } ) ;
1290+
1291+ it ( 'should throw error on incorrectly formatted type union' , ( ) => {
1292+ const tokens = getTokens ( 'Returns `A` | `B`' ) ;
1293+ expect ( ( ) => extractReturnType ( tokens ) ) . toThrow (
1294+ / T y p e u n i o n s m u s t b e f u l l y e n c l o s e d i n b a c k t i c k s / ,
1295+ ) ;
1296+ } ) ;
1297+
1298+ it ( 'should handle returns with failed list parsing' , ( ) => {
1299+ const tokens = getTokens ( 'Returns `Object`\n\n* invalid list item' ) ;
1300+ const result = extractReturnType ( tokens ) ;
1301+ expect ( result . parsedReturnType ) . not . toBeNull ( ) ;
1302+ expect ( result . parsedReturnType ! . type ) . toBe ( 'Object' ) ;
1303+ } ) ;
1304+
1305+ it ( 'should handle description starting with pipe character' , ( ) => {
1306+ const tokens = getTokens ( 'Returns `String` | another thing' ) ;
1307+ expect ( ( ) => extractReturnType ( tokens ) ) . toThrow (
1308+ / T y p e u n i o n s m u s t b e f u l l y e n c l o s e d i n b a c k t i c k s / ,
1309+ ) ;
1310+ } ) ;
1311+ } ) ;
1312+
1313+ describe ( 'rawTypeToTypeInformation edge cases' , ( ) => {
1314+ it ( 'should handle Function type without subTypedKeys' , ( ) => {
1315+ const result = rawTypeToTypeInformation ( 'Function' , '' , null ) ;
1316+ expect ( result . type ) . toBe ( 'Function' ) ;
1317+ expect ( result . parameters ) . toEqual ( [ ] ) ;
1318+ expect ( result . returns ) . toBeNull ( ) ;
1319+ } ) ;
1320+
1321+ it ( 'should handle Function type with subTypedKeys' , ( ) => {
1322+ const md = `
1323+ * \`callback\` Function - The callback
1324+ * \`event\` Event - The event object
1325+ ` ;
1326+ const tokens = getTokens ( md ) ;
1327+ const list = findNextList ( tokens ) ;
1328+ const typedKeys = convertListToTypedKeys ( list ! ) ;
1329+
1330+ const result = rawTypeToTypeInformation ( 'Function' , '' , typedKeys ) ;
1331+ expect ( result . type ) . toBe ( 'Function' ) ;
1332+ expect ( result . parameters ) . toHaveLength ( 2 ) ;
1333+ expect ( result . parameters ! [ 0 ] . name ) . toBe ( 'callback' ) ;
1334+ expect ( result . parameters ! [ 1 ] . name ) . toBe ( 'event' ) ;
1335+ expect ( result . returns ) . toBeNull ( ) ;
1336+ } ) ;
1337+
1338+ it ( 'should handle Object type without subTypedKeys' , ( ) => {
1339+ const result = rawTypeToTypeInformation ( 'Object' , '' , null ) ;
1340+ expect ( result . type ) . toBe ( 'Object' ) ;
1341+ expect ( result . properties ) . toEqual ( [ ] ) ;
1342+ } ) ;
1343+
1344+ it ( 'should handle String type with subTypedKeys' , ( ) => {
1345+ const md = `
1346+ * \`option1\` - First option
1347+ * \`option2\` - Second option
1348+ ` ;
1349+ const tokens = getTokens ( md ) ;
1350+ const list = findNextList ( tokens ) ;
1351+ const typedKeys = convertListToTypedKeys ( list ! ) ;
1352+
1353+ const result = rawTypeToTypeInformation ( 'String' , '' , typedKeys ) ;
1354+ expect ( result . type ) . toBe ( 'String' ) ;
1355+ expect ( result . possibleValues ) . toHaveLength ( 2 ) ;
1356+ expect ( result . possibleValues ! [ 0 ] . value ) . toBe ( 'option1' ) ;
1357+ } ) ;
1358+
1359+ it ( 'should handle Event<> with inner type' , ( ) => {
1360+ const result = rawTypeToTypeInformation ( 'Event<CustomEvent>' , '' , null ) ;
1361+ expect ( result . type ) . toBe ( 'Event' ) ;
1362+ expect ( result . eventPropertiesReference ) . toBeDefined ( ) ;
1363+ expect ( result . eventPropertiesReference ! . type ) . toBe ( 'CustomEvent' ) ;
1364+ } ) ;
1365+
1366+ it ( 'should throw on Event<> with both inner type and parameter list' , ( ) => {
1367+ const md = `* \`foo\` String` ;
1368+ const tokens = getTokens ( md ) ;
1369+ const list = findNextList ( tokens ) ;
1370+ const typedKeys = convertListToTypedKeys ( list ! ) ;
1371+
1372+ expect ( ( ) => rawTypeToTypeInformation ( 'Event<CustomEvent>' , '' , typedKeys ) ) . toThrow (
1373+ / E v e n t < > s h o u l d n o t h a v e d e c l a r e d i n n e r t y p e s A N D a p a r a m e t e r l i s t / ,
1374+ ) ;
1375+ } ) ;
1376+
1377+ it ( 'should throw on Event<> with multiple inner types' , ( ) => {
1378+ expect ( ( ) => rawTypeToTypeInformation ( 'Event<Type1, Type2>' , '' , null ) ) . toThrow (
1379+ / E v e n t < > s h o u l d h a v e a t m o s t o n e i n n e r t y p e / ,
1380+ ) ;
1381+ } ) ;
1382+
1383+ it ( 'should throw on Event<> without inner type or parameter list' , ( ) => {
1384+ expect ( ( ) => rawTypeToTypeInformation ( 'Event<>' , '' , null ) ) . toThrow (
1385+ / E v e n t < > d e c l a r a t i o n w i t h o u t a p a r a m e t e r l i s t / ,
1386+ ) ;
1387+ } ) ;
1388+
1389+ it ( 'should handle Event<> with parameter list' , ( ) => {
1390+ const md = `* \`detail\` String - Event detail` ;
1391+ const tokens = getTokens ( md ) ;
1392+ const list = findNextList ( tokens ) ;
1393+ const typedKeys = convertListToTypedKeys ( list ! ) ;
1394+
1395+ const result = rawTypeToTypeInformation ( 'Event<>' , '' , typedKeys ) ;
1396+ expect ( result . type ) . toBe ( 'Event' ) ;
1397+ expect ( result . eventProperties ) . toHaveLength ( 1 ) ;
1398+ expect ( result . eventProperties ! [ 0 ] . name ) . toBe ( 'detail' ) ;
1399+ } ) ;
1400+
1401+ it ( 'should handle Function<> with generic types' , ( ) => {
1402+ const result = rawTypeToTypeInformation ( 'Function<String, Number, Boolean>' , '' , null ) ;
1403+ expect ( result . type ) . toBe ( 'Function' ) ;
1404+ expect ( result . parameters ) . toHaveLength ( 2 ) ;
1405+ expect ( result . returns ! . type ) . toBe ( 'Boolean' ) ;
1406+ } ) ;
1407+
1408+ it ( 'should handle Function<> without generic params falling back to subTypedKeys' , ( ) => {
1409+ const md = `* \`arg1\` String - First arg` ;
1410+ const tokens = getTokens ( md ) ;
1411+ const list = findNextList ( tokens ) ;
1412+ const typedKeys = convertListToTypedKeys ( list ! ) ;
1413+
1414+ const result = rawTypeToTypeInformation ( 'Function<Boolean>' , '' , typedKeys ) ;
1415+ expect ( result . type ) . toBe ( 'Function' ) ;
1416+ expect ( result . parameters ) . toHaveLength ( 1 ) ;
1417+ expect ( result . parameters ! [ 0 ] . name ) . toBe ( 'arg1' ) ;
1418+ expect ( result . returns ! . type ) . toBe ( 'Boolean' ) ;
1419+ } ) ;
1420+
1421+ it ( 'should throw on generic type without inner types' , ( ) => {
1422+ expect ( ( ) => rawTypeToTypeInformation ( 'GenericType<>' , '' , null ) ) . toThrow (
1423+ / s h o u l d h a v e a t l e a s t o n e i n n e r t y p e / ,
1424+ ) ;
1425+ } ) ;
1426+
1427+ it ( 'should handle generic types with Object inner type and subTypedKeys' , ( ) => {
1428+ const md = `* \`prop\` String - Property` ;
1429+ const tokens = getTokens ( md ) ;
1430+ const list = findNextList ( tokens ) ;
1431+ const typedKeys = convertListToTypedKeys ( list ! ) ;
1432+
1433+ const result = rawTypeToTypeInformation ( 'Promise<Object>' , '' , typedKeys ) ;
1434+ expect ( result . type ) . toBe ( 'Promise' ) ;
1435+ expect ( result . innerTypes ) . toHaveLength ( 1 ) ;
1436+ expect ( result . innerTypes ! [ 0 ] . type ) . toBe ( 'Object' ) ;
1437+ expect ( result . innerTypes ! [ 0 ] . properties ) . toHaveLength ( 1 ) ;
1438+ } ) ;
1439+ } ) ;
1440+
1441+ describe ( 'findContentAfterList' , ( ) => {
1442+ it ( 'should return content starting from heading_close when returnAllOnNoList=true and no list found' , ( ) => {
1443+ const md = `
1444+ ### Heading
1445+
1446+ Some content without a list
1447+
1448+ #### Next Heading
1449+ ` ;
1450+ const tokens = getTokens ( md ) ;
1451+ const result = findContentAfterList ( tokens , true ) ;
1452+ expect ( result . length ) . toBeGreaterThan ( 0 ) ;
1453+ } ) ;
11651454 } ) ;
11661455} ) ;
0 commit comments