Skip to content

Conversation

@boblodgett
Copy link
Contributor

@boblodgett boblodgett commented Dec 17, 2025

Description

This change updates the doc generator to generate client and interface page Code Examples links contained in the example_meta.json file. The checked in example_meta.json file is not the full file which is injected by the build system.

A new "In this article" control is added to the client and interface pages for jumping to the associated sections of the page including the new code examples section. It is page section context aware and will only include the jump links if the section of the page exists. We may apply the control to method and other pages in the future.

Related internal CR for build system modifications and additional context: CR-241670200

Motivation and Context

Backlog: DOTNET-8196 -- Adds code examples links to client and interface pages where available.

Testing

  • Tested in the build system see related internal CR.
  • Unit tests for new functionality
  • Manual testing by local generation of the API documentation

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My code follows the code style of this project
  • My change requires a change to the documentation
  • I have updated the documentation accordingly
  • I have read the README document
  • I have added tests to cover my changes
  • All new and existing tests passed

License

  • I confirm that this pull request can be released under the Apache 2 license

@boblodgett boblodgett changed the title Boblod examples v4 Added Code Examples links to class and interface pages. Dec 17, 2025
@boblodgett boblodgett marked this pull request as ready for review December 17, 2025 07:47
public class ExampleMetadataParser
{
private const string FragmentOutputDirectory = "ExampleFragments";
private const string BaseCodeLibraryUrl = "https://docs.aws.amazon.com/code-library/latest/ug/dotnet_4";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens when these docs are deployed to alpha and integ doc sites, will this hardcoded url work?

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds code examples links to client and interface documentation pages by integrating with an example metadata JSON file (example_meta.json). The changes introduce a new parser to process example metadata, generate HTML fragments, and display them on the generated documentation pages. Additionally, a collapsible "In this article" table of contents is added to help users navigate page sections.

Key Changes:

  • Created ExampleMetadataParser to parse example metadata and generate HTML fragments for code examples
  • Enhanced ClassWriter to include a page-level TOC and code examples section
  • Added JavaScript and CSS for collapsible TOC functionality
  • Configured new command-line options for example metadata file path and error file

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
ExampleMetadataParser.cs New parser that processes example_meta.json and generates HTML fragments for code examples per service
ClassWriter.cs Added page TOC generation and code examples section integration
pagescript.js Added toggleTOC function and scroll handler for collapsible TOC behavior
sdkstyle.css Added CSS styles for collapsible page TOC component
GeneratorOptions.cs Added properties for ExampleMetaJson and ExamplesErrorFile configuration
CommandLineParser.cs Added command-line argument parsing for example metadata options
SdkDocGenerator.cs Orchestrates example fragment generation and cleanup during doc build
doc-build.proj Updated build configuration to pass example metadata parameters
example_meta.json Sample metadata file with Control Tower examples (partial, injected by build system)
ExampleMetadataParserTests.cs Unit tests for the new ExampleMetadataParser functionality
SDKDocGeneratorLib.csproj Added System.Text.Json package dependency

// because any errors in the example_meta.json file must be corrected by the owners of
// the file.
Console.WriteLine($"Continuing without examples. Failed to generate example fragments: {ex.Message}");
File.WriteAllText(examplesErrorFile, $"Failed to generate example fragments: {ex}");
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the catch block, File.WriteAllText is called with examplesErrorFile, but if examplesErrorFile is null or empty (which can happen from the build configuration where ExamplesErrorFile defaults to empty string), this will throw an ArgumentException. Add validation to ensure examplesErrorFile is not null or empty before writing to it, or skip writing the error file if it's not specified.

Suggested change
File.WriteAllText(examplesErrorFile, $"Failed to generate example fragments: {ex}");
if (!string.IsNullOrEmpty(examplesErrorFile))
{
File.WriteAllText(examplesErrorFile, $"Failed to generate example fragments: {ex}");
}

Copilot uses AI. Check for mistakes.
// the file.
Console.WriteLine($"Continuing without examples. Failed to generate example fragments: {ex.Message}");
File.WriteAllText(examplesErrorFile, $"Failed to generate example fragments: {ex}");
CleanupExampleFragments();
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ExampleFragmentsFullPath is set at the start of GenerateExampleFragments but is never reset to empty if an exception occurs. This means if GenerateExampleFragments is called multiple times (e.g., in tests or retry scenarios), CleanupExampleFragments() might attempt to delete a directory path from a previous failed call. Consider resetting ExampleFragmentsFullPath to string.Empty in the catch block after cleanup, or before setting it in the try block.

Suggested change
CleanupExampleFragments();
CleanupExampleFragments();
ExampleFragmentsFullPath = string.Empty;

Copilot uses AI. Check for mistakes.


private static string SanitizeTitle(string title)
{
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SanitizeTitle method does not handle null input. If title is null, this will throw a NullReferenceException. Consider adding null checking to return null or an empty string for null inputs.

Suggested change
{
{
if (title == null)
return null;

Copilot uses AI. Check for mistakes.
Comment on lines +160 to +170
function toggleTOC() {
var tocList = document.getElementById('tocList');
var tocToggle = document.getElementById('tocToggle');
if (tocList.style.display === 'none') {
tocList.style.display = 'block';
tocToggle.innerHTML = '▼';
} else {
tocList.style.display = 'none';
tocToggle.innerHTML = '▶';
}
}
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The toggleTOC function does not check if 'tocList' or 'tocToggle' elements exist before accessing them. If these elements are not present when the function is called, it will throw null reference errors. Add null checks before manipulating these elements.

Copilot uses AI. Check for mistakes.
Comment on lines +173 to +176
if (window.scrollY > 200) {
toc.classList.add('collapsed');
document.getElementById('tocList').style.display = 'none';
document.getElementById('tocToggle').innerHTML = '▶';
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scroll event handler only adds the 'collapsed' class when scrolling down past 200px, but never removes it when scrolling back up. This means once the TOC is collapsed, it will remain in the collapsed/fixed state even if the user scrolls back to the top of the page. Consider adding logic to remove the 'collapsed' class when scrollY is less than or equal to 200.

Suggested change
if (window.scrollY > 200) {
toc.classList.add('collapsed');
document.getElementById('tocList').style.display = 'none';
document.getElementById('tocToggle').innerHTML = '▶';
if (!toc) {
return;
}
if (window.scrollY > 200) {
toc.classList.add('collapsed');
var tocList = document.getElementById('tocList');
var tocToggle = document.getElementById('tocToggle');
if (tocList) {
tocList.style.display = 'none';
}
if (tocToggle) {
tocToggle.innerHTML = '▶';
}
} else {
toc.classList.remove('collapsed');

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this valid? i think its saying once the user scrolls down, and then scrolls back up the TOC will not be visible?

Comment on lines +128 to +135
private static bool IsDotNetExample(Example example)
{

return example.Languages.Values.Any(lang =>
lang.Name.Equals(".NET", StringComparison.OrdinalIgnoreCase) ||
lang.Name.Equals("C#", StringComparison.OrdinalIgnoreCase) ||
lang.Name.Equals("CSharp", StringComparison.OrdinalIgnoreCase));
}
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IsDotNetExample method does not handle cases where example.Languages or example.Languages.Values could be null. If example.Languages is null, calling Values will throw a NullReferenceException. Add a null check before accessing Languages.Values.

Copilot uses AI. Check for mistakes.
Comment on lines +140 to +146
public static string ToUpperFirstCharacter(string s)
{
var txt = s.Substring(0, 1).ToUpperInvariant();
if (s.Length > 1)
txt += s.Substring(1);
return txt;
}
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ToUpperFirstCharacter method does not handle null or empty strings. If a null or empty string is passed, it will throw an ArgumentOutOfRangeException when calling s.Substring(0, 1). Add null/empty string validation before processing.

Copilot uses AI. Check for mistakes.
Comment on lines +164 to +166
var namespaceParts = this._versionType.Namespace.Split('.');
var serviceId = namespaceParts[namespaceParts.Length - 1];
return serviceId;
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GetServiceIdFromNamespace method does not handle cases where the namespace could be null or empty. If this._versionType.Namespace is null, this will throw a NullReferenceException. If it's empty, Split('.') will return an array with one empty element, but accessing the last element would still work. However, null should be handled explicitly.

Suggested change
var namespaceParts = this._versionType.Namespace.Split('.');
var serviceId = namespaceParts[namespaceParts.Length - 1];
return serviceId;
var namespaceValue = this._versionType == null ? null : this._versionType.Namespace;
if (System.String.IsNullOrEmpty(namespaceValue))
return string.Empty;
var namespaceParts = namespaceValue.Split('.');
var serviceId = namespaceParts[namespaceParts.Length - 1];
return serviceId;

Copilot uses AI. Check for mistakes.
Comment on lines +171 to +178
window.addEventListener('scroll', function() {
var toc = document.getElementById('pageTOC');
if (window.scrollY > 200) {
toc.classList.add('collapsed');
document.getElementById('tocList').style.display = 'none';
document.getElementById('tocToggle').innerHTML = '▶';
}
});
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scroll event handler does not check if the 'pageTOC', 'tocList', or 'tocToggle' elements exist before accessing them. If these elements are not present on the page (e.g., on pages that don't use the TOC feature), this will throw null reference errors. Add null checks before accessing these elements.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this valid? are there pages where toc wont exist that this will be executed?

GenerationManifest coreManifest = null;
DeferredTypesProvider deferredTypes = new DeferredTypesProvider(null);

// Generate the Code Examples fragments for all services
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ExampleMetaJson parameter is passed directly to GenerateExampleFragments without checking if it's null or empty. While GenerateExampleFragments does check if the file exists, if options.ExampleMetaJson is null, this will cause File.Exists to throw an ArgumentNullException. Consider adding validation here or ensuring GenerateExampleFragments handles null/empty paths gracefully.

Suggested change
// Generate the Code Examples fragments for all services
// Generate the Code Examples fragments for all services
if (string.IsNullOrEmpty(options.ExampleMetaJson))
{
Info("ERROR: ExampleMetaJson option not set");
return -1;
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants