diff --git a/lib/src/generator/generator_backend.dart b/lib/src/generator/generator_backend.dart
index 43577ce99e..ffc54781ce 100644
--- a/lib/src/generator/generator_backend.dart
+++ b/lib/src/generator/generator_backend.dart
@@ -86,8 +86,7 @@ abstract class GeneratorBackend {
);
}
var e = data.self;
- writer.write(filename, content,
- element: e is Warnable ? e : null);
+ writer.write(filename, content, element: e is Warnable ? e : null);
}
/// Emits JSON describing the [categories] defined by the package.
@@ -122,6 +121,11 @@ abstract class GeneratorBackend {
var data = CategoryTemplateData(options, packageGraph, category);
var content = templates.renderCategory(data);
write(writer, category.filePath, data, content);
+ if (category.filePath != category.redirectFilePath) {
+ var redirectContent = templates.renderCategoryRedirect(data);
+ write(writer, category.redirectFilePath, data, redirectContent);
+ }
+
runtimeStats.incrementAccumulator('writtenCategoryFileCount');
}
diff --git a/lib/src/generator/templates.aot_renderers_for_html.dart b/lib/src/generator/templates.aot_renderers_for_html.dart
index 4f19ebb48b..9333c1b73c 100644
--- a/lib/src/generator/templates.aot_renderers_for_html.dart
+++ b/lib/src/generator/templates.aot_renderers_for_html.dart
@@ -234,6 +234,41 @@ String renderCategory(CategoryTemplateData context0) {
return buffer.toString();
}
+String renderCategoryRedirect(CategoryTemplateData context0) {
+ final buffer = StringBuffer();
+ buffer.write('''
+
+
+
+
+
+
+ New URL
+
+
+''');
+
+ return buffer.toString();
+}
+
String renderClass(ClassTemplateData context0) {
final buffer = StringBuffer();
buffer.write(_renderClass_partial_head_0(context0));
diff --git a/lib/src/generator/templates.dart b/lib/src/generator/templates.dart
index 4fcd71becb..eb624456af 100644
--- a/lib/src/generator/templates.dart
+++ b/lib/src/generator/templates.dart
@@ -12,6 +12,9 @@
@Renderer(#renderCategory, Context(), 'category',
visibleTypes: _visibleTypes)
+@Renderer(#renderCategoryRedirect, Context(),
+ 'category_redirect',
+ visibleTypes: _visibleTypes)
@Renderer(#renderClass, Context(), 'class')
@Renderer(#renderConstructor, Context(), 'constructor')
@Renderer(#renderEnum, Context(), 'enum')
@@ -92,6 +95,7 @@ const _visibleTypes = {
/// The collection of [Template] objects.
abstract class Templates {
String renderCategory(CategoryTemplateData context);
+ String renderCategoryRedirect(CategoryTemplateData context);
String renderClass(ClassTemplateData context);
String renderConstructor(ConstructorTemplateData context);
String renderEnum(EnumTemplateData context);
@@ -141,6 +145,10 @@ class HtmlAotTemplates implements Templates {
String renderCategory(CategoryTemplateData context) =>
aot_renderers_for_html.renderCategory(context);
+ @override
+ String renderCategoryRedirect(CategoryTemplateData context) =>
+ aot_renderers_for_html.renderCategoryRedirect(context);
+
@override
String renderClass(ClassTemplateData context) =>
aot_renderers_for_html.renderClass(context);
@@ -222,6 +230,10 @@ class RuntimeTemplates implements Templates {
String renderCategory(CategoryTemplateData context) =>
runtime_renderers.renderCategory(context, _categoryTemplate);
+ @override
+ String renderCategoryRedirect(CategoryTemplateData context) =>
+ runtime_renderers.renderCategoryRedirect(context, _categoryTemplate);
+
@override
String renderClass(ClassTemplateData context) =>
runtime_renderers.renderClass(context, _classTemplate);
diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart
index cc9d11902d..bc01161928 100644
--- a/lib/src/generator/templates.runtime_renderers.dart
+++ b/lib/src/generator/templates.runtime_renderers.dart
@@ -1846,6 +1846,38 @@ class _Renderer_Category extends RendererBase {
);
},
),
+ 'fileName': Property(
+ getValue: (CT_ c) => c.fileName,
+ renderVariable: (
+ CT_ c,
+ Property self,
+ List remainingNames,
+ ) {
+ if (remainingNames.isEmpty) {
+ return self.getValue(c).toString();
+ }
+ var name = remainingNames.first;
+ var nextProperty = _Renderer_String.propertyMap().getValue(
+ name,
+ );
+ return nextProperty.renderVariable(
+ self.getValue(c) as String,
+ nextProperty,
+ [...remainingNames.skip(1)],
+ );
+ },
+
+ isNullValue: (CT_ c) => false,
+
+ renderValue: (
+ CT_ c,
+ RendererBase r,
+ List ast,
+ StringSink sink,
+ ) {
+ _render_String(c.fileName, ast, r.template, sink, parent: r);
+ },
+ ),
'filePath': Property(
getValue: (CT_ c) => c.filePath,
renderVariable: (
@@ -2155,6 +2187,44 @@ class _Renderer_Category extends RendererBase {
);
},
),
+ 'redirectFilePath': Property(
+ getValue: (CT_ c) => c.redirectFilePath,
+ renderVariable: (
+ CT_ c,
+ Property self,
+ List remainingNames,
+ ) {
+ if (remainingNames.isEmpty) {
+ return self.getValue(c).toString();
+ }
+ var name = remainingNames.first;
+ var nextProperty = _Renderer_String.propertyMap().getValue(
+ name,
+ );
+ return nextProperty.renderVariable(
+ self.getValue(c) as String,
+ nextProperty,
+ [...remainingNames.skip(1)],
+ );
+ },
+
+ isNullValue: (CT_ c) => false,
+
+ renderValue: (
+ CT_ c,
+ RendererBase r,
+ List ast,
+ StringSink sink,
+ ) {
+ _render_String(
+ c.redirectFilePath,
+ ast,
+ r.template,
+ sink,
+ parent: r,
+ );
+ },
+ ),
'referenceChildren': Property(
getValue: (CT_ c) => c.referenceChildren,
renderVariable:
@@ -2285,7 +2355,7 @@ class _Renderer_Category extends RendererBase {
}
}
-String renderCategory(CategoryTemplateData context, Template template) {
+String renderCategoryRedirect(CategoryTemplateData context, Template template) {
var buffer = StringBuffer();
_render_CategoryTemplateData(context, template.ast, template, buffer);
return buffer.toString();
@@ -2543,6 +2613,12 @@ class _Renderer_CategoryTemplateData
}
}
+String renderCategory(CategoryTemplateData context, Template template) {
+ var buffer = StringBuffer();
+ _render_CategoryTemplateData(context, template.ast, template, buffer);
+ return buffer.toString();
+}
+
void _render_Class(
Class context,
List ast,
@@ -19948,7 +20024,7 @@ class _Renderer_Package extends RendererBase {
}
}
-String renderIndex(PackageTemplateData context, Template template) {
+String renderSearchPage(PackageTemplateData context, Template template) {
var buffer = StringBuffer();
_render_PackageTemplateData(context, template.ast, template, buffer);
return buffer.toString();
@@ -20305,13 +20381,13 @@ class _Renderer_PackageTemplateData extends RendererBase {
}
}
-String renderError(PackageTemplateData context, Template template) {
+String renderIndex(PackageTemplateData context, Template template) {
var buffer = StringBuffer();
_render_PackageTemplateData(context, template.ast, template, buffer);
return buffer.toString();
}
-String renderSearchPage(PackageTemplateData context, Template template) {
+String renderError(PackageTemplateData context, Template template) {
var buffer = StringBuffer();
_render_PackageTemplateData(context, template.ast, template, buffer);
return buffer.toString();
diff --git a/lib/src/model/category.dart b/lib/src/model/category.dart
index 5008b3ef0e..225ff7532b 100644
--- a/lib/src/model/category.dart
+++ b/lib/src/model/category.dart
@@ -105,11 +105,17 @@ class Category
late final bool isDocumented =
documentedWhere != DocumentLocation.missing && documentationFile != null;
- String get filePath {
+ String get fileName {
assert(_name != null);
- return 'topics/$_name-topic.html';
+ return '$_name-topic.html';
}
+ String get filePath => 'topics/$fileName';
+
+ /// Prior to dartdoc 8.3.4 the `displayName` was used in the file path
+ /// for category pages. We now create a redirect file here instead.
+ String get redirectFilePath => 'topics/$name-topic.html';
+
@override
String? get href => isCanonical ? '${package.baseHref}$filePath' : null;
diff --git a/lib/templates/category_redirect.html b/lib/templates/category_redirect.html
new file mode 100644
index 0000000000..548f6676ea
--- /dev/null
+++ b/lib/templates/category_redirect.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+ New URL
+
+
diff --git a/test/end2end/model_test.dart b/test/end2end/model_test.dart
index 331f2f9d56..0d1170d860 100644
--- a/test/end2end/model_test.dart
+++ b/test/end2end/model_test.dart
@@ -730,6 +730,11 @@ void main() async {
});
});
+ test('Verify redirectFilePath set', () {
+ var category = packageGraph.publicPackages.first.categories.first;
+ expect(category.redirectFilePath, 'topics/Superb-topic.html');
+ });
+
group('LibraryContainer', () {
late final TestLibraryContainer topLevel;
var sortOrderBasic = ['theFirst', 'second', 'fruit'];
diff --git a/test/templates/category_test.dart b/test/templates/category_test.dart
index 9b7255fd2b..29db4bb567 100644
--- a/test/templates/category_test.dart
+++ b/test/templates/category_test.dart
@@ -74,52 +74,53 @@ analyzer:
dartdocOptions: '''
dartdoc:
categories:
- One:
+ cat1:
markdown: one.md
+ displayName: One
Documented:
markdown: documented.md
''',
libFiles: [
d.file('lib.dart', '''
/// A class.
-/// {@category One}
+/// {@category cat1}
class C1 {}
/// A constant.
-/// {@category One}
+/// {@category cat1}
const c1 = 1;
/// An enum.
-/// {@category One}
+/// {@category cat1}
enum E1 { one, two }
/// A function.
-/// {@category One}
+/// {@category cat1}
void F1() {}
/// A mixin.
-/// {@category One}
+/// {@category cat1}
mixin M1 {}
/// A property.
-/// {@category One}
+/// {@category cat1}
var p1 = 1;
/// A typedef.
-/// {@category One}
+/// {@category cat1}
typedef T1 = void Function();
/// A typedef.
-/// {@category One}
+/// {@category cat1}
// TODO(srawlins): Properly unit-test "typedef pointing to typedef".
typedef T2 = T1;
/// An extension.
-/// {@category One}
+/// {@category cat1}
extension Ex on int {}
/// An extension type.
-/// {@category One}
+/// {@category cat1}
extension type ExType(int it) {}
'''),
d.file('other.dart', '''
@@ -136,7 +137,7 @@ library;
await utils.writeDartdocResources(resourceProvider);
await (await buildDartdoc()).generateDocs();
topicOneLines = resourceProvider
- .getFile(path.join(packagePath, 'doc', 'topics', 'One-topic.html'))
+ .getFile(path.join(packagePath, 'doc', 'topics', 'cat1-topic.html'))
.readAsStringSync()
.split('\n');
indexPageLines = resourceProvider
@@ -145,6 +146,14 @@ library;
.split('\n');
});
+ test('redirect category file created', () async {
+ final redirectContent = resourceProvider
+ .getFile(path.join(packagePath, 'doc', 'topics', 'One-topic.html'))
+ .readAsStringSync();
+
+ expect(redirectContent, contains('Classes'),
+ matches('Classes'),
matches('C1'),
]),
);
@@ -225,7 +234,7 @@ library;
topicOneLines,
containsAllInOrder([
matches('