Skip to content

Commit 7171357

Browse files
authored
Fix seealso cref handling (#168)
* Update test to correctly verify see cref vs seealso cref. * Convert inner seealso crefs to see crefs. Preserve seealsos that are standalone children. * Skip porting seealsos if the CLI argument for member or type is set to true. * Add tests to verify that skipping porting works for members and for types.
1 parent 842204c commit 7171357

File tree

9 files changed

+348
-28
lines changed

9 files changed

+348
-28
lines changed

src/PortToDocs/src/libraries/Configuration.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ private enum Mode
3333
PortMemberProperties,
3434
PortMemberReturns,
3535
PortMemberRemarks,
36+
PortMemberSeeAlsos,
3637
PortMemberSummaries,
3738
PortMemberTypeParams,
3839
PortTypeParams, // Params of a Type
3940
PortTypeRemarks,
41+
PortTypeSeeAlsos,
4042
PortTypeSummaries,
4143
PortTypeTypeParams, // TypeParams of a Type
4244
PreserveInheritDocTag,
@@ -88,13 +90,15 @@ private enum Mode
8890
public bool PortMemberProperties { get; set; } = true;
8991
public bool PortMemberReturns { get; set; } = true;
9092
public bool PortMemberRemarks { get; set; } = true;
93+
public bool PortMemberSeeAlsos { get; set; } = true;
9194
public bool PortMemberSummaries { get; set; } = true;
9295
public bool PortMemberTypeParams { get; set; } = true;
9396
/// <summary>
9497
/// Params of a Type.
9598
/// </summary>
9699
public bool PortTypeParams { get; set; } = true;
97100
public bool PortTypeRemarks { get; set; } = true;
101+
public bool PortTypeSeeAlsos { get; set; } = true;
98102
public bool PortTypeSummaries { get; set; } = true;
99103
/// <summary>
100104
/// TypeParams of a Type.
@@ -395,6 +399,10 @@ public static Configuration GetCLIArguments(string[] args)
395399
mode = Mode.PortMemberSummaries;
396400
break;
397401

402+
case "-PORTMEMBERSEEALSOS":
403+
mode = Mode.PortMemberSeeAlsos;
404+
break;
405+
398406
case "-PORTMEMBERTYPEPARAMS":
399407
mode = Mode.PortMemberTypeParams;
400408
break;
@@ -407,6 +415,10 @@ public static Configuration GetCLIArguments(string[] args)
407415
mode = Mode.PortTypeRemarks;
408416
break;
409417

418+
case "-PORTTYPESEEALSOS":
419+
mode = Mode.PortTypeSeeAlsos;
420+
break;
421+
410422
case "-PORTTYPESUMMARIES":
411423
mode = Mode.PortTypeSummaries;
412424
break;
@@ -516,6 +528,13 @@ public static Configuration GetCLIArguments(string[] args)
516528
break;
517529
}
518530

531+
case Mode.PortMemberSeeAlsos:
532+
{
533+
config.PortMemberSeeAlsos = ParseOrExit(arg, "Port member SeeAlsos");
534+
mode = Mode.Initial;
535+
break;
536+
}
537+
519538
case Mode.PortMemberSummaries:
520539
{
521540
config.PortMemberSummaries = ParseOrExit(arg, "Port member Summaries");
@@ -544,6 +563,13 @@ public static Configuration GetCLIArguments(string[] args)
544563
break;
545564
}
546565

566+
case Mode.PortTypeSeeAlsos:
567+
{
568+
config.PortTypeSeeAlsos = ParseOrExit(arg, "Port type SeeAlsos");
569+
mode = Mode.Initial;
570+
break;
571+
}
572+
547573
case Mode.PortTypeSummaries:
548574
{
549575
config.PortTypeSummaries = ParseOrExit(arg, "Port Type Summaries");
@@ -802,6 +828,12 @@ Enable or disable finding and porting Member remarks.
802828
Usage example:
803829
-PortMemberRemarks false
804830
831+
-PortMemberSeeAlsos bool Default is true (ports Member seealsos).
832+
Enable or disable finding and porting Member seealsos.
833+
These are found directly under the Docs xml element.
834+
Usage example:
835+
-PortMemberSeeAlsos false
836+
805837
-PortMemberSummaries bool Default is true (ports Member summaries).
806838
Enable or disable finding and porting Member summaries.
807839
Usage example:
@@ -822,6 +854,12 @@ Enable or disable finding and porting Type remarks.
822854
Usage example:
823855
-PortTypeRemarks false
824856
857+
-PortTypeSeeAlsos bool Default is true (ports Type seealsos).
858+
Enable or disable finding and porting Type seealsos.
859+
These are found directly under the Docs xml element.
860+
Usage example:
861+
-PortTypeSeeAlsos false
862+
825863
-PortTypeSummaries bool Default is true (ports Type summaries).
826864
Enable or disable finding and porting Type summaries.
827865
Usage example:

src/PortToDocs/src/libraries/Docs/DocsAPI.cs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
@@ -18,7 +18,7 @@ internal abstract class DocsAPI : IDocsAPI
1818
private List<DocsTypeParameter>? _typeParameters;
1919
private List<DocsTypeParam>? _typeParams;
2020
private List<DocsAssemblyInfo>? _assemblyInfos;
21-
private List<string>? _seeAlsoCrefs;
21+
private List<DocsSeeAlso>? _seeAlsos;
2222
private List<string>? _altMemberCrefs;
2323
private List<DocsRelated>? _relateds;
2424
private XElement? _xInheritDoc = null;
@@ -140,22 +140,22 @@ public List<DocsTypeParam> TypeParams
140140
}
141141
}
142142

143-
public List<string> SeeAlsoCrefs
143+
public List<DocsSeeAlso> SeeAlsos
144144
{
145145
get
146146
{
147-
if (_seeAlsoCrefs == null)
147+
if (_seeAlsos == null)
148148
{
149149
if (Docs != null)
150150
{
151-
_seeAlsoCrefs = Docs.Elements("seealso").Select(x => XmlHelper.GetAttributeValue(x, "cref")).ToList();
151+
_seeAlsos = Docs.Elements("seealso").Select(x => new DocsSeeAlso(this, x)).ToList();
152152
}
153153
else
154154
{
155-
_seeAlsoCrefs = new();
155+
_seeAlsos = new();
156156
}
157157
}
158-
return _seeAlsoCrefs;
158+
return _seeAlsos;
159159
}
160160
}
161161

@@ -310,6 +310,15 @@ public DocsTypeParam AddTypeParam(string name, string value)
310310
return new DocsTypeParam(this, typeParam);
311311
}
312312

313+
public DocsSeeAlso AddSeeAlso(string cref)
314+
{
315+
XElement seeAlso = new XElement("seealso");
316+
seeAlso.SetAttributeValue("cref", cref);
317+
Docs.Add(seeAlso);
318+
Changed = true;
319+
return new DocsSeeAlso(this, seeAlso);
320+
}
321+
313322
// For Types, these elements are called TypeSignature.
314323
// For Members, these elements are called MemberSignature.
315324
protected abstract string GetApiSignatureDocId();

src/PortToDocs/src/libraries/Docs/DocsMember.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Xml.Linq;
5+
6+
namespace ApiDocsSync.PortToDocs.Docs;
7+
8+
internal class DocsSeeAlso
9+
{
10+
private readonly XElement XESeeAlso;
11+
12+
public IDocsAPI ParentAPI
13+
{
14+
get; private set;
15+
}
16+
17+
public string Cref => XmlHelper.GetAttributeValue(XESeeAlso, "cref");
18+
19+
public DocsSeeAlso(IDocsAPI parentAPI, XElement xSeeAlso)
20+
{
21+
ParentAPI = parentAPI;
22+
XESeeAlso = xSeeAlso;
23+
}
24+
25+
public override string ToString() => $"seealso cref={Cref}";
26+
}

src/PortToDocs/src/libraries/IntelliSenseXml/IntelliSenseXmlMember.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
@@ -107,6 +107,19 @@ public IEnumerable<IntelliSenseXmlException> Exceptions
107107
}
108108
}
109109

110+
private List<IntelliSenseXmlSeeAlso>? _seeAlsos;
111+
public IEnumerable<IntelliSenseXmlSeeAlso> SeeAlsos
112+
{
113+
get
114+
{
115+
if (_seeAlsos == null)
116+
{
117+
_seeAlsos = XEMember.Elements("seealso").Select(x => new IntelliSenseXmlSeeAlso(x)).ToList();
118+
}
119+
return _seeAlsos;
120+
}
121+
}
122+
110123
private string? _summary;
111124
public string Summary
112125
{
@@ -116,6 +129,7 @@ public string Summary
116129
{
117130
XElement? xElement = XEMember.Element("summary");
118131
_summary = (xElement != null) ? XmlHelper.GetNodesInPlainText(xElement) : string.Empty;
132+
_summary = XmlHelper.ReplaceSeeAlsos(_summary);
119133
}
120134
return _summary;
121135
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Xml.Linq;
5+
6+
namespace ApiDocsSync.PortToDocs.IntelliSenseXml;
7+
8+
internal class IntelliSenseXmlSeeAlso(XElement xeSeeAlso)
9+
{
10+
public XElement XESeeAlso
11+
{
12+
get;
13+
private set;
14+
} = xeSeeAlso;
15+
16+
private string _cref = string.Empty;
17+
public string Cref
18+
{
19+
get
20+
{
21+
if (string.IsNullOrWhiteSpace(_cref))
22+
{
23+
_cref = XmlHelper.GetAttributeValue(XESeeAlso, "cref");
24+
}
25+
return _cref;
26+
}
27+
}
28+
29+
public override string ToString() => $"SeeAlso cref={Cref}";
30+
}

src/PortToDocs/src/libraries/ToDocsPorter.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ private void PortMissingCommentsForType(DocsType dTypeToUpdate)
239239
TryPortMissingReturnsForMember(dTypeToUpdate, mc.Returns);
240240
}
241241

242+
TryPortMissingSeeAlsosForMember(dTypeToUpdate, tsTypeToPort);
243+
242244
if (dTypeToUpdate.Changed)
243245
{
244246
ModifiedTypes.Add(docId);
@@ -309,6 +311,8 @@ private void PortMissingCommentsForMember(DocsMember dMemberToUpdate)
309311
TryPortMissingReturnsForMember(dMemberToUpdate, mc.Returns, mc.IsEII);
310312
}
311313

314+
TryPortMissingSeeAlsosForMember(dMemberToUpdate, tsMemberToPort);
315+
312316
if (dMemberToUpdate.Changed)
313317
{
314318
ModifiedAPIs.Add(dMemberToUpdate.DocId);
@@ -964,6 +968,24 @@ private void TryPortMissingExceptionsForMember(DocsMember dMemberToUpdate, Intel
964968
}
965969
}
966970

971+
private void TryPortMissingSeeAlsosForMember(DocsAPI dAPIToUpdate, IntelliSenseXmlMember? tsMemberToPort)
972+
{
973+
if ((dAPIToUpdate.Kind == APIKind.Member && !Config.PortMemberSeeAlsos) || (dAPIToUpdate.Kind == APIKind.Type && !Config.PortTypeSeeAlsos) || tsMemberToPort == null)
974+
{
975+
return;
976+
}
977+
978+
foreach (IntelliSenseXmlSeeAlso tsSeeAlso in tsMemberToPort.SeeAlsos)
979+
{
980+
if (!dAPIToUpdate.SeeAlsos.Any(x => x.Cref == tsSeeAlso.Cref))
981+
{
982+
dAPIToUpdate.AddSeeAlso(tsSeeAlso.Cref);
983+
PrintModifiedMember("seealso", dAPIToUpdate.FilePath, tsSeeAlso.Cref, isEII: false);
984+
TotalModifiedIndividualElements++;
985+
}
986+
}
987+
}
988+
967989
// If a Param is found in a DocsType or a DocsMember that did not exist in the IntelliSense xml member, it's possible the param was unexpectedly saved in the IntelliSense xml comments with a different name, so the user gets prompted to look for it.
968990
private bool TryPromptParam(DocsParam oldDParam, IntelliSenseXmlMember tsMember, out IntelliSenseXmlParam? newTsParam)
969991
{

src/PortToDocs/src/libraries/XmlHelper.cs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
@@ -33,6 +33,11 @@ internal class XmlHelper
3333
{ "></see>", " />" }
3434
};
3535

36+
private static readonly Dictionary<string, string> _replaceableSeeAlsos = new Dictionary<string, string>
37+
{
38+
{ "seealso cref", "see cref" }
39+
};
40+
3641
private static readonly Dictionary<string, string> _replaceableNormalElementRegexPatterns = new Dictionary<string, string>
3742
{
3843
// Replace primitives: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types
@@ -297,26 +302,19 @@ private static string RemoveUndesiredEndlines(string value)
297302
return value.Trim();
298303
}
299304

300-
private static string ReplaceMarkdownPatterns(string value)
301-
{
302-
string updatedValue = value;
303-
foreach (KeyValuePair<string, string> kvp in _replaceableMarkdownPatterns)
304-
{
305-
if (updatedValue.Contains(kvp.Key))
306-
{
307-
updatedValue = updatedValue.Replace(kvp.Key, kvp.Value);
308-
}
309-
}
310-
return updatedValue;
311-
}
312-
313305
internal static string ReplaceExceptionPatterns(string value) =>
314-
Regex.Replace(value, @"[\r\n\t ]+\-[ ]?or[ ]?\-[\r\n\t ]+", "\n\n-or-\n\n");
306+
Regex.Replace(value, @"[\r\n\t ]+\-[ ]*(or|OR)[ ]*\-[\r\n\t ]+", "\n\n-or-\n\n");
307+
308+
internal static string ReplaceSeeAlsos(string value) => ReplacePatterns(value, _replaceableSeeAlsos);
309+
310+
private static string ReplaceMarkdownPatterns(string value) => ReplacePatterns(value, _replaceableMarkdownPatterns);
311+
312+
private static string ReplaceNormalElementPatterns(string value) => ReplacePatterns(value, _replaceableNormalElementPatterns);
315313

316-
private static string ReplaceNormalElementPatterns(string value)
314+
private static string ReplacePatterns(string value, Dictionary<string, string> patterns)
317315
{
318316
string updatedValue = value;
319-
foreach (KeyValuePair<string, string> kvp in _replaceableNormalElementPatterns)
317+
foreach (KeyValuePair<string, string> kvp in patterns)
320318
{
321319
if (updatedValue.Contains(kvp.Key))
322320
{

0 commit comments

Comments
 (0)