/
SandcastleProject.cs
2379 lines (2026 loc) · 105 KB
/
SandcastleProject.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//===============================================================================================================
// System : Sandcastle Help File Builder Utilities
// File : SandcastleProject.cs
// Author : Eric Woodruff (Eric@EWoodruff.us)
// Updated : 02/01/2024
// Note : Copyright 2006-2024, Eric Woodruff, All rights reserved
//
// This file contains the project class.
//
// This code is published under the Microsoft Public License (Ms-PL). A copy of the license should be
// distributed with the code and can be found at the project website: https://GitHub.com/EWSoftware/SHFB. This
// notice, the author's name, and all copyright notices must remain intact in all applications, documentation,
// and source files.
//
// Version Date Who Comments
// ==============================================================================================================
#region Older History
// 1.0.0.0 08/03/2006 EFW Created the code
// 1.1.0.0 08/28/2006 EFW Added various new options for the August CTP
// 1.2.0.0 09/04/2006 EFW Added new properties to support namespace summaries and project summary comments
// 1.3.1.0 09/26/2006 EFW Added the ShowMissing* properties
// 1.3.1.0 10/02/2006 EFW Added support for the September CTP and the Document* properties
// 1.3.2.0 11/03/2006 EFW Added the NamingMethod property
// 1.3.3.1 11/24/2006 EFW Added the SyntaxFilters property, support for build component configurations, and
// other stuff.
// 1.3.4.0 12/24/2006 EFW Added WorkingPath project property. Reworked the load and save code to use
// reflection for most properties to simplify the code and support setting them via the
// command line from the console mode builder. Converted folder properties to
// FolderPath objects.
// 1.4.0.0 02/02/2007 EFW Converted PresentationStyle to a string with a type converter listing the
// presentation folders. Added FooterText property.
// 1.4.0.2 05/11/2007 EFW Missing namespace messages are now optional
// 1.5.0.2 07/03/2007 EFW Added support to additional content site map
// 1.5.1.0 07/20/2007 EFW Added ApiFilter and KeepLogFile project properties
// 1.5.1.0 08/24/2007 EFW Added support for the inherited private/internal framework member flags
// 1.5.2.0 09/10/2007 EFW Added support for plug-in configurations
// 1.6.0.0 09/30/2007 EFW Added support for transforming *.topic files
// 1.6.0.1 10/14/2007 EFW Added support for ShowFeedbackControl and SdkLinkTarget
// 1.6.0.2 11/01/2007 EFW Reworked to support better handling of components
// 1.6.0.5 02/20/2008 EFW Added the FeedbackEMailLinkText property
// 1.6.0.7 03/21/2008 EFW Added Help 2 and ShowMissingTypeParam properties. Removed the PurgeDuplicateTopics
// option. Added the BuildLogFile property. Started laying the foundations for
// conceptual content support. ContentSiteMap and TopicFileTransform were made
// sub-properties of the additional content collection to connect them with it and to
// prevent associating them with conceptual content.
// 1.8.0.0 06/20/2008 EFW Converted the project to use an MSBuild file.
// 1.8.0.1 12/14/2008 EFW Updated for use with .NET 3.5 and MSBuild 3.5. Added support for user-defined
// project properties. Added support for ShowMissingIncludeTargets.
// 1.8.0.3 07/05/2009 EFW Added support for MS Help Viewer format
// 1.8.0.3 11/10/2009 EFW Changed SyntaxFilters property to a string to support custom syntax filter build
// components.
// 1.8.0.3 11/19/2009 EFW Added support for AutoDocumentDisposeMethods
// 1.8.0.3 12/06/2009 EFW Removed support for ShowFeedbackControl
// 1.9.0.0 06/19/2010 EFW Added properties to support MS Help Viewer. Removed ProjectLinkType property.
// Replaced SdkLinkType with help format specific SDK link type properties.
// 1.9.1.0 07/09/2010 EFW Updated for use with .NET 4.0 and MSBuild 4.0
// 1.9.2.0 01/16/2011 EFW Updated to support selection of Silverlight Framework versions
// 1.9.3.2 08/20/2011 EFW Updated to support selection of .NET Portable Framework versions
// 1.9.4.0 04/08/2012 EFW Merged changes for VS2010 style from Don Fehr. Added BuildAssemblerVerbosity
// property. Added Support for XAML configuration files.
// 1.9.5.0 09/10/2012 EFW Updated to use the new framework definition file for the .NET Framework versions.
// Added the CatalogName property for Help Viewer 2.0 support.
// 1.9.6.0 10/13/2012 EFW Removed the BrandingPackageName and SelfBranded properties. Added support for
// transform component arguments.
#endregion
// 1.9.9.0 11/30/2013 EFW Merged changes from Stazzz to support namespace grouping
// ------- 12/17/2013 EFW Removed the SandcastlePath property and all references to it
// 12/20/2013 EFW Added support for the ComponentPath project property
// 05/03/2015 EFW Removed support for the MS Help 2 file format
// 01/22/2016 EFW Added SaveComponentCacheCapacity property
// 08/25/2016 EFW Added support for the SourceCodeBasePath property
// 09/22/2017 EFW Added support for EditorBrowsable and Browsable attribute visibility settings
// 12/10/2017 EFW Added support for the WebsiteAdContent and SearchResultsDisplayVersion properties
//===============================================================================================================
// Ignore Spelling: Fehr Stazzz param typeparam safeprojectname apifilter documentationsources namespacesummaries
// Ignore Spelling: componentconfigurations pluginconfigurations transformcomponentarguments helpfileformat
// Ignore Spelling: frameworkversion presentationstyle visibleitems
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using Microsoft.Build.Evaluation;
using Sandcastle.Core;
using Sandcastle.Core.Reflection;
using Sandcastle.Core.PresentationStyle.Transformation;
using SandcastleBuilder.Utils.BuildComponent;
using SandcastleBuilder.Utils.ConceptualContent;
using SandcastleBuilder.Utils.Design;
namespace SandcastleBuilder.Utils
{
/// <summary>
/// This class represents all of the properties that make up a Sandcastle Help File Builder project
/// </summary>
public sealed class SandcastleProject : IBasePathProvider, IContentFileProvider, IDisposable
{
#region Constants
//=====================================================================
// NOTE: When this changes, update the version in Resources\ProjectTemplate.txt and in the
// SancastleBuilderPackage project templates.
/// <summary>
/// The schema version used in the saved project files
/// </summary>
public static readonly Version SchemaVersion = new Version(2017, 9, 26, 0);
/// <summary>The default configuration</summary>
public const string DefaultConfiguration = "Debug";
/// <summary>The default platform</summary>
public const string DefaultPlatform = "AnyCPU";
#endregion
#region Private data members
//=====================================================================
// Bad characters for the vendor name property
private static readonly Regex reBadVendorNameChars = new Regex(@"[:\\/\.,#&]");
// These are used to decode hex values in the copyright text
private static readonly Regex reDecode = new Regex(@"\\x[0-9a-f]{2,4}", RegexOptions.IgnoreCase);
private readonly MatchEvaluator characterMatchEval, buildVarMatchEval;
// MS Build and property items
private readonly Project msBuildProject;
private Dictionary<string, ProjectProperty> projectPropertyCache; // MSBuild property cache
private readonly bool removeProjectWhenDisposed;
// Local property info cache
private static Dictionary<string, PropertyInfo> propertyCache = InitializePropertyCache();
private static PropertyDescriptorCollection pdcCache;
// Path and build-related properties
private FolderPath hhcPath, workingPath, componentPath, sourceCodeBasePath;
private FilePath buildLogFile;
private string outputPath, frameworkVersion;
private int maximumGroupParts;
// Help file properties
private string helpTitle, htmlHelpName, copyrightHref, copyrightText, feedbackEMailAddress,
feedbackEMailLinkText, headerText, footerText, projectSummary, rootNamespaceTitle, presentationStyle,
helpFileVersion, syntaxFilters, vendorName, productTitle, topicVersion, tocParentId, tocParentVersion,
catalogProductId, catalogVersion, catalogName;
private CultureInfo language;
private int tocOrder;
// Collection valued properties
private DocumentationSourceCollection docSources;
private ApiFilterCollection apiFilter;
private NamespaceSummaryItemCollection namespaceSummaries;
private ComponentConfigurationDictionary componentConfigs;
private PlugInConfigurationDictionary plugInConfigs;
#endregion
#region Miscellaneous properties
//=====================================================================
/// <summary>
/// This returns a collection of restricted property names that cannot be used for user-defined property
/// names.
/// </summary>
public static IReadOnlyCollection<string> RestrictedProperties { get; } =
new HashSet<string>(StringComparer.OrdinalIgnoreCase) {
"AssemblyName", "Configuration", "CustomAfterSHFBTargets", "CustomBeforeSHFBTargets",
"DumpLogOnFailure", "Name", "Platform", "PostBuildEvent", "PreBuildEvent", "ProjectGuid",
"RootNamespace", "RunPostBuildEvent", "SccAuxPath", "SccLocalPath", "SccProjectName",
"SccProvider", "SchemaVersion", "SHFBSchemaVersion", "TargetFrameworkVersion",
"TransformComponentArguments", "Verbose" };
/// <summary>
/// This read-only property returns the MSBuild project property cache
/// </summary>
private Dictionary<string, ProjectProperty> ProjectPropertyCache
{
get
{
// There can be duplicate versions of the properties so pick the last one as it will contain
// the value to use. Property names are case-insensitive.
if(projectPropertyCache == null)
projectPropertyCache = msBuildProject.AllEvaluatedProperties.GroupBy(
p => p.Name.ToLowerInvariant()).Select(g => g.Last()).ToDictionary(
p => p.Name, StringComparer.OrdinalIgnoreCase);
return projectPropertyCache;
}
}
/// <summary>
/// This read-only property is used to get the underlying MSBuild project
/// </summary>
public Project MSBuildProject => msBuildProject;
/// <summary>
/// This read-only property is used to get whether or not the project is using final values for the
/// project properties.
/// </summary>
/// <value>If true, final values (i.e. evaluated values used at build time) are being returned by the
/// properties in this instance.</value>
[XmlIgnore]
public bool UsingFinalValues { get; }
/// <summary>
/// This read-only property is used to get the filename for the project
/// </summary>
public string Filename => msBuildProject.FullPath;
/// <summary>
/// This is used to get or set the configuration to use when building the project
/// </summary>
/// <value>This value is used for project documentation sources and project references so that the
/// correct items are used from them.</value>
[XmlIgnore]
public string Configuration
{
get
{
string config = null;
if(msBuildProject != null)
{
if(!msBuildProject.GlobalProperties.TryGetValue(BuildItemMetadata.Configuration, out config))
config = null;
}
if(String.IsNullOrEmpty(config))
config = DefaultConfiguration;
return config;
}
set
{
if(String.IsNullOrWhiteSpace(value))
value = DefaultConfiguration;
msBuildProject.SetGlobalProperty(BuildItemMetadata.Configuration, value);
msBuildProject.ReevaluateIfNecessary();
}
}
/// <summary>
/// This is used to get or set the platform to use when building the project
/// </summary>
/// <value>This value is used for project documentation sources and project references so that the
/// correct items are used from them.</value>
[XmlIgnore]
public string Platform
{
get
{
string platform = null;
if(msBuildProject != null)
{
if(!msBuildProject.GlobalProperties.TryGetValue(BuildItemMetadata.Platform, out platform))
platform = null;
}
if(String.IsNullOrEmpty(platform))
platform = DefaultPlatform;
return platform;
}
set
{
if(String.IsNullOrWhiteSpace(value))
value = DefaultPlatform;
msBuildProject.SetGlobalProperty(BuildItemMetadata.Platform, value);
msBuildProject.ReevaluateIfNecessary();
}
}
/// <summary>
/// This is used to get or set the MSBuild <c>OutDir</c> property value that is defined when using Team
/// Build.
/// </summary>
/// <value>This value is used for project documentation sources and project references so that the
/// correct items are used from them.</value>
[XmlIgnore]
public string MSBuildOutDir
{
get
{
string outDir = null;
if(msBuildProject != null)
{
// Ignore ".\" as that's our default.
if(msBuildProject.GlobalProperties.TryGetValue(BuildItemMetadata.OutDir, out outDir))
if(outDir == @".\")
outDir = null;
}
return outDir;
}
set
{
msBuildProject.SetGlobalProperty(BuildItemMetadata.OutDir, (value ?? String.Empty).Trim());
msBuildProject.ReevaluateIfNecessary();
}
}
/// <summary>
/// This is used to get the dirty state of the project
/// </summary>
public bool IsDirty => msBuildProject.Xml.HasUnsavedChanges;
/// <summary>
/// This read-only property is used to get the build log file location
/// </summary>
/// <value>If <see cref="BuildLogFile"/> is set, it returns its value. If not set, it returns the full
/// path created by using the <see cref="OutputPath"/> property value and a filename of
/// <strong>LastBuild.log</strong>.</value>
public string LogFileLocation
{
get
{
string path;
if(buildLogFile.Path.Length != 0)
return buildLogFile.ToString();
if(Path.IsPathRooted(outputPath))
path = outputPath;
else
path = Path.Combine(Path.GetDirectoryName(msBuildProject.FullPath), outputPath);
return Path.GetFullPath(path + "LastBuild.log");
}
}
/// <summary>
/// This read-only property returns an enumerable list of documentation sources to use in building the
/// help file.
/// </summary>
public IEnumerable<DocumentationSource> DocumentationSources
{
get
{
if(docSources == null)
docSources = new DocumentationSourceCollection(this);
return docSources;
}
}
/// <summary>
/// This returns an enumerable list of all build items in the project that represent folders and files
/// </summary>
public IEnumerable<FileItem> FileItems
{
get
{
List<string> buildActions = new List<string>(Enum.GetNames(typeof(BuildAction)));
foreach(ProjectItem item in msBuildProject.AllEvaluatedItems)
if(buildActions.IndexOf(item.ItemType) != -1)
yield return new FileItem(this, item);
}
}
/// <summary>
/// This read-only property returns an enumerable list of image references contained in the project
/// </summary>
/// <returns>An enumerable list of image references if any are found in the project</returns>
/// <remarks>Only images with IDs are returned</remarks>
public IEnumerable<ImageReference> ImagesReferences
{
get
{
ImageReference imageRef;
string id;
foreach(ProjectItem item in msBuildProject.GetItems(BuildAction.Image.ToString()))
{
id = item.GetMetadataValue(BuildItemMetadata.ImageId);
if(!String.IsNullOrWhiteSpace(id))
{
imageRef = new ImageReference(new FilePath(item.UnevaluatedInclude, this), id)
{
AlternateText = item.GetMetadataValue(BuildItemMetadata.AlternateText)
};
if(!Boolean.TryParse(item.GetMetadataValue(BuildItemMetadata.CopyToMedia), out bool copyToMedia))
copyToMedia = false;
imageRef.CopyToMedia = copyToMedia;
yield return imageRef;
}
}
}
}
/// <summary>
/// This returns an enumerable list of transform component arguments
/// </summary>
/// <remarks>These are passed as arguments to the XSL transformations used by the <b>BuildAssembler</b>
/// <c>TransformComponent</c>.</remarks>
/// <returns>An enumerable list of transform component arguments</returns>
public IEnumerable<TransformationArgument> TransformComponentArguments
{
get
{
var argsProp = msBuildProject.GetProperty("TransformComponentArguments");
if(argsProp != null && !String.IsNullOrEmpty(argsProp.UnevaluatedValue))
{
// Use a reader to ignore namespaces
using(var xr = new XmlTextReader("<Args>" + argsProp.UnevaluatedValue + "</Args>",
XmlNodeType.Element, new XmlParserContext(null, null, null, XmlSpace.Preserve))
{ Namespaces = false })
{
xr.MoveToContent();
foreach(var arg in XElement.Load(xr, LoadOptions.PreserveWhitespace).Descendants("Argument"))
yield return new TransformationArgument(arg);
}
}
}
}
/// <summary>
/// This read-only property returns an enumerable list of all user-defined properties
/// </summary>
/// <returns>An enumerable list of all properties determined not to be help file builder project
/// properties, MSBuild build engine related properties, or environment variables.</returns>
public IEnumerable<ProjectProperty> UserDefinedProperties
{
get
{
if(msBuildProject != null && propertyCache != null)
foreach(ProjectProperty prop in msBuildProject.AllEvaluatedProperties)
{
if(!prop.IsEnvironmentProperty && !prop.IsGlobalProperty && !prop.IsImported &&
!prop.IsReservedProperty && !propertyCache.ContainsKey(prop.Name) &&
!RestrictedProperties.Contains(prop.Name))
{
yield return prop;
}
}
}
}
#endregion
#region Project and namespace summary properties
//=====================================================================
/// <summary>
/// This read-only property is used to get the project summary comments
/// </summary>
/// <remarks>These notes will appear in the root namespaces page if entered</remarks>
[EscapeValue]
public string ProjectSummary
{
get => projectSummary;
set => projectSummary = (value ?? String.Empty).Trim();
}
/// <summary>
/// This read-only property returns the list of namespace summaries
/// </summary>
public NamespaceSummaryItemCollection NamespaceSummaries
{
get
{
if(namespaceSummaries == null)
{
namespaceSummaries = new NamespaceSummaryItemCollection();
var nsProperty = msBuildProject.GetProperty("NamespaceSummaries");
if(nsProperty != null && !String.IsNullOrWhiteSpace(nsProperty.UnevaluatedValue))
namespaceSummaries.FromXml(nsProperty.UnevaluatedValue);
}
return namespaceSummaries;
}
}
#endregion
#region Path properties
//=====================================================================
/// <summary>
/// This property is used to get or set the path to a folder containing additional, project-specific
/// build components.
/// </summary>
/// <value>If left blank, the current project's folder is searched instead</value>
public FolderPath ComponentPath
{
get => componentPath;
set
{
if(value == null)
value = new FolderPath(this);
componentPath = value;
}
}
/// <summary>
/// This property is used to get or set the base path used to locate source code for the documented
/// assemblies.
/// </summary>
/// <value>If left blank, source context information will be omitted from the reflection data</value>
public FolderPath SourceCodeBasePath
{
get => sourceCodeBasePath;
set
{
if(value == null)
value = new FolderPath(this);
sourceCodeBasePath = value;
}
}
/// <summary>
/// This is used to get or set whether or not to issue a warning if a source code context could not be
/// determined for a type.
/// </summary>
/// <value>This is false by default and missing source context issues will be reported as informational
/// messages. If set to true, they are reported as warnings that MSBuild will also report.</value>
public bool WarnOnMissingSourceContext { get; set; }
/// <summary>
/// This property is used to get or set the path to the HTML Help 1 compiler (HHC.EXE)
/// </summary>
/// <value>You only need to set this if the builder cannot determine the path for itself</value>
public FolderPath HtmlHelp1xCompilerPath
{
get => hhcPath;
set
{
if(value == null)
value = new FolderPath(this);
hhcPath = value;
}
}
/// <summary>
/// This property is used to get or set the path to which the help files will be generated
/// </summary>
/// <remarks><para>The default is to create it in a folder called <strong>.\Help</strong> in the same
/// folder as the project file.</para>
///
/// <para><strong>Warning:</strong> If building a web site, the output folder's prior content will be
/// erased without warning prior to copying the new web site content to it!</para></remarks>
public string OutputPath
{
get => outputPath;
set
{
if(String.IsNullOrWhiteSpace(value))
value = @".\Help\";
else
value = FolderPath.TerminatePath(value);
outputPath = value;
}
}
/// <summary>
/// This is used to get or set the path to the working folder used during the build process to store the
/// intermediate files.
/// </summary>
/// <value><para>This can be used to perform the build in a different location with a shorter path if you
/// encounter errors due to long file path names. If not specified, it defaults to a folder called
/// <strong>.\Working</strong> under the folder specified by the <see cref="OutputPath"/> property.</para>
///
/// <para><strong>Warning:</strong> All files and folders in the path specified in this property will be
/// erased without warning when the build starts.</para></value>
public FolderPath WorkingPath
{
get => workingPath;
set
{
if(value == null)
value = new FolderPath(this);
workingPath = value;
}
}
/// <summary>
/// This read-only property returns an enumerable list of folders to search for additional build
/// components, plug-ins, presentation styles, and syntax generators.
/// </summary>
public IEnumerable<string> ComponentSearchPaths
{
get
{
// Components from NuGet packages should have set a SHFBComponentPath item so that we can find
// them. These are always searched first.
foreach(var cp in msBuildProject.GetItems("SHFBComponentPath"))
yield return cp.EvaluatedInclude;
// Components in the component path will override those if duplicates are found. Only return it
// if it isn't the project path.
string projectPath = Path.GetDirectoryName(msBuildProject.FullPath);
if(!String.IsNullOrWhiteSpace(componentPath) && !projectPath.Equals(componentPath, StringComparison.OrdinalIgnoreCase))
yield return componentPath;
// And finally, components in the current project path will override all of the above if
// duplicates are found.
yield return projectPath;
}
}
#endregion
#region Build properties
//=====================================================================
/// <summary>
/// This read-only property is used to get the build assembler tool verbosity level
/// </summary>
/// <value>The default is <c>AllMessages</c> to report all messages</value>
/// <remarks>Setting this property to <c>OnlyWarningsAndErrors</c> or <c>OnlyErrors</c> can
/// significantly reduce the size of the build log for large projects.</remarks>
public BuildAssemblerVerbosity BuildAssemblerVerbosity { get; private set; }
/// <summary>
/// This property is used to get or set whether intermediate files are deleted after a successful build
/// </summary>
/// <value>The default value is true</value>
public bool CleanIntermediates { get; set; }
/// <summary>
/// This property is used to get or set whether or not the log file is retained after a successful build
/// </summary>
/// <value>The default value is true</value>
public bool KeepLogFile { get; set; }
/// <summary>
/// This read-only property is used to get the path and filename of the build log file
/// </summary>
/// <value>If not specified, a default name of <strong>LastBuild.log</strong> is used and the file is
/// saved in the path identified in the <see cref="OutputPath" /> property.</value>
public FilePath BuildLogFile
{
get => buildLogFile;
private set
{
if(value == null)
value = new FilePath(this);
buildLogFile = value;
}
}
/// <summary>
/// This read-only property is used to get the help file format generated by the build process
/// </summary>
/// <value>The default is to produce an HTML Help 1 format file</value>
/// <remarks>If building a web site, the output folder will be cleared before the new content is copied
/// to it.</remarks>
public HelpFileFormats HelpFileFormat { get; private set; }
/// <summary>
/// This read-only property is used to get whether or not to disable the custom Code Block Component so
/// that <c><code></c> elements are rendered in their standard format by the Sandcastle XSL
/// transformations.
/// </summary>
/// <value>The default is false so that the Code Block Component is used by default</value>
public bool DisableCodeBlockComponent { get; private set; }
/// <summary>
/// This is used to get or set the .NET Framework version used to resolve references to system types
/// (basic .NET Framework, Silverlight, Portable, etc.).
/// </summary>
/// <remarks>If set to null, it will default to the most recent version of the basic .NET Framework
/// installed. The build engine will adjust this at build time if necessary based on the framework
/// types and versions found in the documentation sources.</remarks>
[EscapeValue]
public string FrameworkVersion
{
get => frameworkVersion;
set
{
// Let bad values through. The property pages or the build engine will catch bad values if
// necessary.
if(String.IsNullOrWhiteSpace(value))
value = ReflectionDataSetDictionary.DefaultFrameworkTitle;
frameworkVersion = value;
}
}
/// <summary>
/// This read-only property is used to get whether or not the HTML rendered by <strong>BuildAssembler</strong>
/// is indented.
/// </summary>
/// <value>This is mainly a debugging aid. Leave it set to false, the default, to produce more compact
/// HTML.</value>
public bool IndentHtml { get; private set; }
/// <summary>
/// This read-only property is used to get the build assembler Save Component writer task cache capacity
/// </summary>
/// <value>The default is 100 to limit the cache to 100 entries</value>
/// <remarks>Decrease the value to conserve memory, increase it to help with build speed at the expense
/// of memory used. Set it to zero to allow an unbounded cache for the writer task (best speed at the
/// expense of memory used).</remarks>
public int SaveComponentCacheCapacity { get; private set; }
/// <summary>
/// This read-only property is used to get a dictionary of build component configurations
/// </summary>
/// <remarks>This allows you to configure the settings for third party build components if they
/// support it.</remarks>
public ComponentConfigurationDictionary ComponentConfigurations
{
get
{
if(componentConfigs == null)
{
componentConfigs = new ComponentConfigurationDictionary();
var compConfigProperty = msBuildProject.GetProperty("ComponentConfigurations");
if(compConfigProperty != null && !String.IsNullOrWhiteSpace(compConfigProperty.UnevaluatedValue))
componentConfigs.FromXml(compConfigProperty.UnevaluatedValue);
}
return componentConfigs;
}
}
/// <summary>
/// This read-only property is used to get a dictionary of build process plug-in configurations
/// </summary>
/// <remarks>This allows you to select and configure the settings for third party build process plug-ins</remarks>
public PlugInConfigurationDictionary PlugInConfigurations
{
get
{
if(plugInConfigs == null)
{
plugInConfigs = new PlugInConfigurationDictionary();
var plugInConfigProperty = msBuildProject.GetProperty("PlugInConfigurations");
if(plugInConfigProperty != null && !String.IsNullOrWhiteSpace(plugInConfigProperty.UnevaluatedValue))
plugInConfigs.FromXml(plugInConfigProperty.UnevaluatedValue);
}
return plugInConfigs;
}
}
#endregion
#region Help file properties
//=====================================================================
/// <summary>
/// This read-only property is used to get the placement of any additional and conceptual content items
/// in the table of contents.
/// </summary>
/// <value>The default is to place additional and conceptual content items above the namespaces</value>
public ContentPlacement ContentPlacement { get; private set; }
/// <summary>
/// This read-only property is used to get whether or not all pages should be marked with a "preliminary
/// documentation" warning in the page header.
/// </summary>
public bool Preliminary { get; private set; }
/// <summary>
/// This read-only property is used to get whether or not a root namespace entry is added to the table of
/// contents to act as a container for the namespaces from the documented assemblies.
/// </summary>
/// <value>If true, a root <strong>Namespaces</strong> table of contents entry will be created as the
/// container of the namespaces in the documented assemblies. If false, the default, the namespaces are
/// listed in the table of contents as root entries.</value>
public bool RootNamespaceContainer { get; private set; }
/// <summary>
/// This read-only property is used to get an alternate title for the root namespaces page and the root
/// table of contents container that appears when <see cref="RootNamespaceContainer"/> is set to true.
/// </summary>
/// <value>If left blank (the default), the localized version of the text "Namespaces" will be used</value>
[EscapeValue]
public string RootNamespaceTitle
{
get => rootNamespaceTitle;
private set => rootNamespaceTitle = (value ?? String.Empty).Trim();
}
/// <summary>
/// This read-only property is used to get whether namespace grouping is enabled. The presentation style
/// must have support for namespace grouping in order for the feature to work.
/// </summary>
/// <value>If <c>true</c>, namespace grouping is enabled. Otherwise, namespace grouping is not enabled</value>
/// <remarks>Namespace groups are determined automatically and may be documented as well</remarks>
public bool NamespaceGrouping { get; private set; }
/// <summary>
/// This read-only property is used to get the maximum number of namespace parts to consider when
/// namespace grouping is enabled.
/// </summary>
/// <value>The minimum and default is 2. A higher value results in more namespace groups</value>
/// <remarks>Namespace groups are determined automatically and may be documented as well</remarks>
public int MaximumGroupParts
{
get => maximumGroupParts;
private set
{
if(value < 2)
value = 2;
maximumGroupParts = value;
}
}
/// <summary>
/// This read-only property is used to get or set the help file's title
/// </summary>
[EscapeValue]
public string HelpTitle
{
get => helpTitle;
private set
{
if(String.IsNullOrWhiteSpace(value))
value = "A Sandcastle Documented Class Library";
else
value = value.Trim();
helpTitle = value;
}
}
/// <summary>
/// This read-only property is used to get the name of the compiled help file
/// </summary>
/// <remarks>Do not include a path or the extension. For MS Help Viewer builds, avoid periods,
/// ampersands, and pound signs as they are not valid in the help file name.</remarks>
[EscapeValue]
public string HtmlHelpName
{
get => htmlHelpName;
private set
{
if(String.IsNullOrWhiteSpace(value))
value = "Documentation";
else
value = value.Trim();
htmlHelpName = value;
}
}
/// <summary>
/// This read-only property is used to get the version number applied to the help file
/// </summary>
/// <remarks>The default is 1.0.0.0</remarks>
[EscapeValue]
public string HelpFileVersion
{
get => helpFileVersion;
private set
{
if(String.IsNullOrWhiteSpace(value))
value = "1.0.0.0";
else
value = value.Trim();
helpFileVersion = value;
}
}
/// <summary>
/// This read-only property is used to get the language option for the help file and to determine which
/// set of presentation resource files to use.
/// </summary>
/// <value>If a matching set of presentation resources cannot be found for the specified language, the
/// US English set will be used.</value>
/// <remarks>The MS Help Viewer 1.0 Catalog ID is composed of the <see cref="CatalogProductId"/>, the
/// <see cref="CatalogVersion"/>, and the <c>Language</c> code. For example, the English Visual Studio 10
/// catalog is <c>VS_100_EN-US</c>.</remarks>
public CultureInfo Language
{
get => language;
private set
{
if(value == null || value == CultureInfo.InvariantCulture)
value = new CultureInfo("en-US");
language = value;
}
}
/// <summary>
/// This read-only property is used to get the URL to use as the link for the copyright notice
/// </summary>
/// <value>If not set, the <see cref="CopyrightText"/> (if any) is not turned into a clickable link</value>
[EscapeValue]
public string CopyrightHref
{
get => copyrightHref;
private set => copyrightHref = (value ?? String.Empty).Trim();
}
/// <summary>
/// This read-only property is used to get the copyright notice that appears in the footer of each page
/// </summary>
/// <remarks>If not set, no copyright note will appear. If a <see cref="CopyrightHref" /> is specified
/// without copyright text, the URL appears instead.</remarks>
[EscapeValue]
public string CopyrightText
{
get => copyrightText;
private set => copyrightText = (value ?? String.Empty).Trim();
}
/// <summary>
/// This read-only property is used to get the copyright notice that appears in the footer of each page
/// with any hex value place holders replaced with their actual character.
/// </summary>
public string DecodedCopyrightText => reDecode.Replace(copyrightText, characterMatchEval);
/// <summary>
/// This read-only property is used to get the feedback e-mail address that appears in the footer of each
/// page.
/// </summary>
/// <remarks>If not set, no feedback link will appear. If <see cref="FeedbackEMailLinkText"/> is set,
/// that text will appear as the text for the link. If not set, the e-mail address is used as the link
/// text.</remarks>
[EscapeValue]
public string FeedbackEMailAddress
{
get => feedbackEMailAddress;
private set => feedbackEMailAddress = (value ?? String.Empty).Trim();
}
/// <summary>
/// This read-only property is used to get the feedback e-mail link text that appears in the feedback
/// e-mail link in the footer of each page.
/// </summary>
/// <remarks>If set, this text will appear as the link text for the <see cref="FeedbackEMailAddress"/>
/// link. If not set, the e-mail address is used for the link text.</remarks>
[EscapeValue]
public string FeedbackEMailLinkText
{
get => feedbackEMailLinkText;
private set => feedbackEMailLinkText = (value ?? String.Empty).Trim();
}
/// <summary>
/// This read-only property is used to get additional text that should appear in the header of every page
/// </summary>
[EscapeValue]
public string HeaderText
{
get => headerText;
private set => headerText = (value ?? String.Empty).Trim();
}
/// <summary>
/// This read-only property is used to get additional text that should appear in the footer of every page
/// </summary>
[EscapeValue]
public string FooterText
{
get => footerText;
private set => footerText = (value ?? String.Empty).Trim();
}
/// <summary>
/// This read-only property is used to get the target window for external SDK links
/// </summary>
/// <value>The default is <c>Blank</c> to open the topics in a new window. This option only has an
/// effect on the <see cref="HtmlSdkLinkType"/>, <see cref="MSHelpViewerSdkLinkType"/>, and
/// <see cref="WebsiteSdkLinkType"/> properties if they are set to <c>Msdn</c>.</value>
public SdkLinkTarget SdkLinkTarget { get; private set; }
/// <summary>
/// This read-only property is used to get the presentation style for the help topic pages
/// </summary>
/// <value>The default is defined by <see cref="Constants.DefaultPresentationStyle" qualifyHint="true" /></value>
[EscapeValue]