@@ -15,6 +15,7 @@ public record ConfigurationFile : DocumentationFile
1515 private readonly IFileInfo _sourceFile ;
1616 private readonly IDirectoryInfo _rootPath ;
1717 private readonly BuildContext _context ;
18+ private readonly int _depth ;
1819 public string ? Project { get ; }
1920 public Glob [ ] Exclude { get ; } = [ ] ;
2021
@@ -28,12 +29,13 @@ public record ConfigurationFile : DocumentationFile
2829 private readonly Dictionary < string , string > _substitutions = new ( StringComparer . OrdinalIgnoreCase ) ;
2930 public IReadOnlyDictionary < string , string > Substitutions => _substitutions ;
3031
31- public ConfigurationFile ( IFileInfo sourceFile , IDirectoryInfo rootPath , BuildContext context )
32+ public ConfigurationFile ( IFileInfo sourceFile , IDirectoryInfo rootPath , BuildContext context , int depth = 0 , string parentPath = "" )
3233 : base ( sourceFile , rootPath )
3334 {
3435 _sourceFile = sourceFile ;
3536 _rootPath = rootPath ;
3637 _context = context ;
38+ _depth = depth ;
3739 if ( ! sourceFile . Exists )
3840 {
3941 Project = "unknown" ;
@@ -81,7 +83,13 @@ public ConfigurationFile(IFileInfo sourceFile, IDirectoryInfo rootPath, BuildCon
8183 ExternalLinkHosts . Add ( host ) ;
8284 break ;
8385 case "toc" :
84- var entries = ReadChildren ( entry , string . Empty ) ;
86+ if ( depth > 1 )
87+ {
88+ EmitError ( $ "toc.yml files may only be linked from docset.yml", entry . Key ) ;
89+ break ;
90+ }
91+
92+ var entries = ReadChildren ( entry , parentPath ) ;
8593
8694 TableOfContents = entries ;
8795 break ;
@@ -115,20 +123,19 @@ private List<ITocItem> ReadChildren(KeyValuePair<YamlNode, YamlNode> entry, stri
115123 return entries ;
116124 }
117125
118- foreach ( var tocEntry in sequence . Children . OfType < YamlMappingNode > ( ) )
119- {
120- var tocItem = ReadChild ( tocEntry , parentPath ) ;
121- if ( tocItem is not null )
122- entries . Add ( tocItem ) ;
123- }
126+ entries . AddRange (
127+ sequence . Children . OfType < YamlMappingNode > ( )
128+ . SelectMany ( tocEntry => ReadChild ( tocEntry , parentPath ) ?? [ ] )
129+ ) ;
124130
125131 return entries ;
126132 }
127133
128- private ITocItem ? ReadChild ( YamlMappingNode tocEntry , string parentPath )
134+ private IEnumerable < ITocItem > ? ReadChild ( YamlMappingNode tocEntry , string parentPath )
129135 {
130136 string ? file = null ;
131137 string ? folder = null ;
138+ ConfigurationFile ? toc = null ;
132139 var fileFound = false ;
133140 var folderFound = false ;
134141 IReadOnlyCollection < ITocItem > ? children = null ;
@@ -137,6 +144,9 @@ private List<ITocItem> ReadChildren(KeyValuePair<YamlNode, YamlNode> entry, stri
137144 var key = ( ( YamlScalarNode ) entry . Key ) . Value ;
138145 switch ( key )
139146 {
147+ case "toc" :
148+ toc = ReadNestedToc ( entry , parentPath , out fileFound ) ;
149+ break ;
140150 case "file" :
141151 file = ReadFile ( entry , parentPath , out fileFound ) ;
142152 break ;
@@ -150,15 +160,23 @@ private List<ITocItem> ReadChildren(KeyValuePair<YamlNode, YamlNode> entry, stri
150160 }
151161 }
152162
163+ if ( toc is not null )
164+ {
165+ foreach ( var f in toc . Files )
166+ Files . Add ( f ) ;
167+
168+ return [ new FolderReference ( $ "{ parentPath } ". TrimStart ( '/' ) , folderFound , toc . TableOfContents ) ] ;
169+ }
170+
153171 if ( file is not null )
154- return new TocFile ( $ "{ parentPath } /{ file } ". TrimStart ( '/' ) , fileFound , children ?? [ ] ) ;
172+ return [ new FileReference ( $ "{ parentPath } /{ file } ". TrimStart ( '/' ) , fileFound , children ?? [ ] ) ] ;
155173
156174 if ( folder is not null )
157175 {
158176 if ( children is null )
159177 ImplicitFolders . Add ( parentPath . TrimStart ( '/' ) ) ;
160178
161- return new TocFolder ( $ "{ parentPath } ". TrimStart ( '/' ) , folderFound , children ?? [ ] ) ;
179+ return [ new FolderReference ( $ "{ parentPath } ". TrimStart ( '/' ) , folderFound , children ?? [ ] ) ] ;
162180 }
163181
164182 return null ;
@@ -226,6 +244,29 @@ private Dictionary<string, string> ReadDictionary(KeyValuePair<YamlNode, YamlNod
226244 return file ;
227245 }
228246
247+ private ConfigurationFile ? ReadNestedToc ( KeyValuePair < YamlNode , YamlNode > entry , string parentPath , out bool found )
248+ {
249+ found = false ;
250+ var tocPath = ReadString ( entry ) ;
251+ if ( tocPath is null )
252+ {
253+ EmitError ( $ "Empty toc: reference", entry . Key ) ;
254+ return null ;
255+ }
256+
257+ var rootPath = _context . ReadFileSystem . DirectoryInfo . New ( Path . Combine ( _rootPath . FullName , tocPath ) ) ;
258+ var path = Path . Combine ( rootPath . FullName , "toc.yml" ) ;
259+ var source = _context . ReadFileSystem . FileInfo . New ( path ) ;
260+ if ( ! source . Exists )
261+ EmitError ( $ "Nested toc: '{ source . FullName } ' does not exist", entry . Key ) ;
262+ else
263+ found = true ;
264+
265+ var nestedConfiguration = new ConfigurationFile ( source , _rootPath , _context , _depth + 1 , tocPath ) ;
266+ return nestedConfiguration ;
267+ }
268+
269+
229270 private string ? ReadString ( KeyValuePair < YamlNode , YamlNode > entry )
230271 {
231272 if ( entry . Value is YamlScalarNode scalar )
0 commit comments