Skip to content

Make redirect pages for categories #4037

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions lib/src/generator/generator_backend.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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');
}

Expand Down
35 changes: 35 additions & 0 deletions lib/src/generator/templates.aot_renderers_for_html.dart
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,41 @@ String renderCategory(CategoryTemplateData context0) {
return buffer.toString();
}

String renderCategoryRedirect(CategoryTemplateData context0) {
final buffer = StringBuffer();
buffer.write('''<!DOCTYPE html>
<html lang="en">
<head>
<link rel="canonical" href="''');
if (context0.useBaseHref) {
var context1 = context0.htmlBase;
buffer.write(context0.htmlBase);
}
buffer.writeEscaped(context0.self.href);
buffer.write('''" />
<meta http-equiv="refresh" content="0; url=''');
if (context0.useBaseHref) {
var context2 = context0.htmlBase;
buffer.write(context0.htmlBase);
}
buffer.writeEscaped(context0.self.href);
buffer.write('''" />
</head>
<body>
<p><a href="''');
if (context0.useBaseHref) {
var context3 = context0.htmlBase;
buffer.write(context0.htmlBase);
}
buffer.writeEscaped(context0.self.href);
buffer.write('''">New URL</a></p>
</body>
</html>
''');

return buffer.toString();
}

String renderClass(ClassTemplateData context0) {
final buffer = StringBuffer();
buffer.write(_renderClass_partial_head_0(context0));
Expand Down
12 changes: 12 additions & 0 deletions lib/src/generator/templates.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

@Renderer(#renderCategory, Context<CategoryTemplateData>(), 'category',
visibleTypes: _visibleTypes)
@Renderer(#renderCategoryRedirect, Context<CategoryTemplateData>(),
'category_redirect',
visibleTypes: _visibleTypes)
@Renderer(#renderClass, Context<ClassTemplateData>(), 'class')
@Renderer(#renderConstructor, Context<ConstructorTemplateData>(), 'constructor')
@Renderer(#renderEnum, Context<EnumTemplateData>(), 'enum')
Expand Down Expand Up @@ -92,6 +95,7 @@ const _visibleTypes = {
/// The collection of [Template] objects.
abstract class Templates {
String renderCategory(CategoryTemplateData context);
String renderCategoryRedirect(CategoryTemplateData context);
String renderClass<T extends Class>(ClassTemplateData context);
String renderConstructor(ConstructorTemplateData context);
String renderEnum(EnumTemplateData context);
Expand Down Expand Up @@ -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<T extends Class>(ClassTemplateData context) =>
aot_renderers_for_html.renderClass(context);
Expand Down Expand Up @@ -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<T extends Class>(ClassTemplateData context) =>
runtime_renderers.renderClass(context, _classTemplate);
Expand Down
84 changes: 80 additions & 4 deletions lib/src/generator/templates.runtime_renderers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1846,6 +1846,38 @@ class _Renderer_Category extends RendererBase<Category> {
);
},
),
'fileName': Property(
getValue: (CT_ c) => c.fileName,
renderVariable: (
CT_ c,
Property<CT_> self,
List<String> 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<CT_> r,
List<MustachioNode> ast,
StringSink sink,
) {
_render_String(c.fileName, ast, r.template, sink, parent: r);
},
),
'filePath': Property(
getValue: (CT_ c) => c.filePath,
renderVariable: (
Expand Down Expand Up @@ -2155,6 +2187,44 @@ class _Renderer_Category extends RendererBase<Category> {
);
},
),
'redirectFilePath': Property(
getValue: (CT_ c) => c.redirectFilePath,
renderVariable: (
CT_ c,
Property<CT_> self,
List<String> 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<CT_> r,
List<MustachioNode> ast,
StringSink sink,
) {
_render_String(
c.redirectFilePath,
ast,
r.template,
sink,
parent: r,
);
},
),
'referenceChildren': Property(
getValue: (CT_ c) => c.referenceChildren,
renderVariable:
Expand Down Expand Up @@ -2285,7 +2355,7 @@ class _Renderer_Category extends RendererBase<Category> {
}
}

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();
Expand Down Expand Up @@ -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<MustachioNode> ast,
Expand Down Expand Up @@ -19948,7 +20024,7 @@ class _Renderer_Package extends RendererBase<Package> {
}
}

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();
Expand Down Expand Up @@ -20305,13 +20381,13 @@ class _Renderer_PackageTemplateData extends RendererBase<PackageTemplateData> {
}
}

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();
Expand Down
10 changes: 8 additions & 2 deletions lib/src/model/category.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
10 changes: 10 additions & 0 deletions lib/templates/category_redirect.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="canonical" href="{{ #useBaseHref }}{{ #htmlBase }}{{{ htmlBase }}}{{ /htmlBase }}{{ /useBaseHref }}{{ self.href }}" />
<meta http-equiv="refresh" content="0; url={{ #useBaseHref }}{{ #htmlBase }}{{{ htmlBase }}}{{ /htmlBase }}{{ /useBaseHref }}{{ self.href }}" />
</head>
<body>
<p><a href="{{ #useBaseHref }}{{ #htmlBase }}{{{ htmlBase }}}{{ /htmlBase }}{{ /useBaseHref }}{{ self.href }}">New URL</a></p>
</body>
</html>
5 changes: 5 additions & 0 deletions test/end2end/model_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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'];
Expand Down
Loading