Skip to content

Commit 12113f2

Browse files
committed
Introduce a new URL for library pages, at index.html
Fixes #1346 This "moves" the URL of each library from, e.g. 'package-two_lib2/package-two_lib2-library.html' to 'package-two_lib2/index.html', such that we can have links with 'package-two_lib2'. The old URLs are preserved via redirecting HTML files. (HTTP redirects are more standard and recommended, but dartdoc does not contain an HTTP server; HTTP redirects could be implemented at the hosting server, which is different for different doc hosts (Google Storage, Firebase, ...). Instead we use simpler HTML redirects. In fact, a given backend host could use the HTML redirecting files as a database to inform HTTP redirect rules, that need to be implemented differently for each backend. So dartdoc now produces redirecting files, but a given backend could instead return an HTTP 301 Permanent Redirect response when requesting one of the redirecting files.) This adds a negligible number of files (1 per documented library), and a negligible number of bytes (tiny redirect files), but actually is probably a net negative in terms of bytes, as many links are now shortened, removing the HTML file name of library URLs.
1 parent 4c82b49 commit 12113f2

22 files changed

+1927
-1655
lines changed

lib/resources/docs.dart.js

Lines changed: 1613 additions & 1569 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/resources/docs.dart.js.map

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/src/generator/generator_backend.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,14 @@ abstract class GeneratorBackend {
179179
runtimeStats.incrementAccumulator('writtenFunctionFileCount');
180180
}
181181

182-
/// Emits documentation content for the [library].
182+
/// Emits documentation content for the [library], and the content for the
183+
/// library's previous location (which just redirects to the new location).
183184
void generateLibrary(PackageGraph packageGraph, Library library) {
184185
var data = LibraryTemplateData(options, packageGraph, library);
185186
var content = templates.renderLibrary(data);
187+
var redirectContent = templates.renderLibraryRedirect(data);
186188
write(writer, library.filePath, data, content);
189+
write(writer, library.redirectingPath, data, redirectContent);
187190
runtimeStats.incrementAccumulator('writtenLibraryFileCount');
188191
}
189192

lib/src/generator/templates.aot_renderers_for_html.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,29 @@ String renderLibrary(LibraryTemplateData context0) {
11371137
return buffer.toString();
11381138
}
11391139

1140+
String renderLibraryRedirect(LibraryTemplateData context0) {
1141+
final buffer = StringBuffer();
1142+
buffer.write('''<!DOCTYPE html>
1143+
<html lang="en">
1144+
<head>
1145+
<meta http-equiv="refresh" content="0; url=''');
1146+
if (context0.useBaseHref) {
1147+
var context1 = context0.htmlBase;
1148+
buffer.write(context0.htmlBase);
1149+
buffer.writeEscaped(context0.self.href);
1150+
}
1151+
buffer.write('''" />
1152+
</head>
1153+
<body>
1154+
<p><a href="''');
1155+
buffer.writeEscaped(context0.self.href);
1156+
buffer.write('''">Redirect</a></p>
1157+
</body>
1158+
</html>''');
1159+
1160+
return buffer.toString();
1161+
}
1162+
11401163
String renderMethod(MethodTemplateData context0) {
11411164
final buffer = StringBuffer();
11421165
buffer.write(_renderMethod_partial_head_0(context0));

lib/src/generator/templates.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
@Renderer(#renderFunction, Context<FunctionTemplateData>(), 'function')
2323
@Renderer(#renderIndex, Context<PackageTemplateData>(), 'index')
2424
@Renderer(#renderLibrary, Context<LibraryTemplateData>(), 'library')
25+
@Renderer(
26+
#renderLibraryRedirect, Context<LibraryTemplateData>(), 'library_redirect')
2527
@Renderer(#renderMethod, Context<MethodTemplateData>(), 'method')
2628
@Renderer(#renderMixin, Context<MixinTemplateData>(), 'mixin')
2729
@Renderer(#renderProperty, Context<PropertyTemplateData>(), 'property')
@@ -99,6 +101,7 @@ abstract class Templates {
99101
String renderFunction(FunctionTemplateData context);
100102
String renderIndex(PackageTemplateData context);
101103
String renderLibrary(LibraryTemplateData context);
104+
String renderLibraryRedirect(LibraryTemplateData context);
102105
String renderMethod(MethodTemplateData context);
103106
String renderMixin(MixinTemplateData context);
104107
String renderProperty(PropertyTemplateData context);
@@ -174,6 +177,10 @@ class HtmlAotTemplates implements Templates {
174177
String renderLibrary(LibraryTemplateData context) =>
175178
aot_renderers_for_html.renderLibrary(context);
176179

180+
@override
181+
String renderLibraryRedirect(LibraryTemplateData context) =>
182+
aot_renderers_for_html.renderLibraryRedirect(context);
183+
177184
@override
178185
String renderMethod(MethodTemplateData context) =>
179186
aot_renderers_for_html.renderMethod(context);
@@ -251,6 +258,10 @@ class RuntimeTemplates implements Templates {
251258
String renderLibrary(LibraryTemplateData context) =>
252259
runtime_renderers.renderLibrary(context, _libraryTemplate);
253260

261+
@override
262+
String renderLibraryRedirect(LibraryTemplateData context) =>
263+
runtime_renderers.renderLibraryRedirect(context, _libraryTemplate);
264+
254265
@override
255266
String renderMethod(MethodTemplateData context) =>
256267
runtime_renderers.renderMethod(context, _methodTemplate);

lib/src/generator/templates.runtime_renderers.dart

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2760,28 +2760,6 @@ class _Renderer_Container extends RendererBase<Container> {
27602760
parent: r);
27612761
},
27622762
),
2763-
'filePath': Property(
2764-
getValue: (CT_ c) => c.filePath,
2765-
renderVariable:
2766-
(CT_ c, Property<CT_> self, List<String> remainingNames) {
2767-
if (remainingNames.isEmpty) {
2768-
return self.getValue(c).toString();
2769-
}
2770-
var name = remainingNames.first;
2771-
var nextProperty =
2772-
_Renderer_String.propertyMap().getValue(name);
2773-
return nextProperty.renderVariable(
2774-
self.getValue(c) as String,
2775-
nextProperty,
2776-
[...remainingNames.skip(1)]);
2777-
},
2778-
isNullValue: (CT_ c) => false,
2779-
renderValue: (CT_ c, RendererBase<CT_> r,
2780-
List<MustachioNode> ast, StringSink sink) {
2781-
_render_String(c.filePath, ast, r.template, sink,
2782-
parent: r);
2783-
},
2784-
),
27852763
'hasAvailableInstanceFields': Property(
27862764
getValue: (CT_ c) => c.hasAvailableInstanceFields,
27872765
renderVariable: (CT_ c, Property<CT_> self,
@@ -4283,6 +4261,28 @@ class _Renderer_Enum extends RendererBase<Enum> {
42834261
parent: r, getters: _invisibleGetters['EnumElement']!);
42844262
},
42854263
),
4264+
'fileName': Property(
4265+
getValue: (CT_ c) => c.fileName,
4266+
renderVariable:
4267+
(CT_ c, Property<CT_> self, List<String> remainingNames) {
4268+
if (remainingNames.isEmpty) {
4269+
return self.getValue(c).toString();
4270+
}
4271+
var name = remainingNames.first;
4272+
var nextProperty =
4273+
_Renderer_String.propertyMap().getValue(name);
4274+
return nextProperty.renderVariable(
4275+
self.getValue(c) as String,
4276+
nextProperty,
4277+
[...remainingNames.skip(1)]);
4278+
},
4279+
isNullValue: (CT_ c) => false,
4280+
renderValue: (CT_ c, RendererBase<CT_> r,
4281+
List<MustachioNode> ast, StringSink sink) {
4282+
_render_String(c.fileName, ast, r.template, sink,
4283+
parent: r);
4284+
},
4285+
),
42864286
'hasPublicEnumValues': Property(
42874287
getValue: (CT_ c) => c.hasPublicEnumValues,
42884288
renderVariable: (CT_ c, Property<CT_> self,
@@ -8443,6 +8443,28 @@ class _Renderer_Library extends RendererBase<Library> {
84438443
parent: r));
84448444
},
84458445
),
8446+
'redirectingPath': Property(
8447+
getValue: (CT_ c) => c.redirectingPath,
8448+
renderVariable:
8449+
(CT_ c, Property<CT_> self, List<String> remainingNames) {
8450+
if (remainingNames.isEmpty) {
8451+
return self.getValue(c).toString();
8452+
}
8453+
var name = remainingNames.first;
8454+
var nextProperty =
8455+
_Renderer_String.propertyMap().getValue(name);
8456+
return nextProperty.renderVariable(
8457+
self.getValue(c) as String,
8458+
nextProperty,
8459+
[...remainingNames.skip(1)]);
8460+
},
8461+
isNullValue: (CT_ c) => false,
8462+
renderValue: (CT_ c, RendererBase<CT_> r,
8463+
List<MustachioNode> ast, StringSink sink) {
8464+
_render_String(c.redirectingPath, ast, r.template, sink,
8465+
parent: r);
8466+
},
8467+
),
84468468
'referenceChildren': Property(
84478469
getValue: (CT_ c) => c.referenceChildren,
84488470
renderVariable: (CT_ c, Property<CT_> self,
@@ -8808,6 +8830,12 @@ class _Renderer_LibraryTemplateData extends RendererBase<LibraryTemplateData> {
88088830
}
88098831
}
88108832

8833+
String renderLibraryRedirect(LibraryTemplateData context, Template template) {
8834+
var buffer = StringBuffer();
8835+
_render_LibraryTemplateData(context, template.ast, template, buffer);
8836+
return buffer.toString();
8837+
}
8838+
88118839
class _Renderer_Locatable extends RendererBase<Locatable> {
88128840
static final Map<Type, Object> _propertyMapCache = {};
88138841
static Map<String, Property<CT_>> propertyMap<CT_ extends Locatable>() =>
@@ -11050,8 +11078,8 @@ class _Renderer_ModelFunctionTyped extends RendererBase<ModelFunctionTyped> {
1105011078
parent: r);
1105111079
},
1105211080
),
11053-
'filePath': Property(
11054-
getValue: (CT_ c) => c.filePath,
11081+
'fileName': Property(
11082+
getValue: (CT_ c) => c.fileName,
1105511083
renderVariable:
1105611084
(CT_ c, Property<CT_> self, List<String> remainingNames) {
1105711085
if (remainingNames.isEmpty) {
@@ -11068,7 +11096,7 @@ class _Renderer_ModelFunctionTyped extends RendererBase<ModelFunctionTyped> {
1106811096
isNullValue: (CT_ c) => false,
1106911097
renderValue: (CT_ c, RendererBase<CT_> r,
1107011098
List<MustachioNode> ast, StringSink sink) {
11071-
_render_String(c.filePath, ast, r.template, sink,
11099+
_render_String(c.fileName, ast, r.template, sink,
1107211100
parent: r);
1107311101
},
1107411102
),
@@ -12482,13 +12510,13 @@ class _Renderer_PackageTemplateData extends RendererBase<PackageTemplateData> {
1248212510
}
1248312511
}
1248412512

12485-
String renderIndex(PackageTemplateData context, Template template) {
12513+
String renderError(PackageTemplateData context, Template template) {
1248612514
var buffer = StringBuffer();
1248712515
_render_PackageTemplateData(context, template.ast, template, buffer);
1248812516
return buffer.toString();
1248912517
}
1249012518

12491-
String renderError(PackageTemplateData context, Template template) {
12519+
String renderIndex(PackageTemplateData context, Template template) {
1249212520
var buffer = StringBuffer();
1249312521
_render_PackageTemplateData(context, template.ast, template, buffer);
1249412522
return buffer.toString();
@@ -14666,8 +14694,8 @@ class _Renderer_TopLevelVariable extends RendererBase<TopLevelVariable> {
1466614694
parent: r);
1466714695
},
1466814696
),
14669-
'filePath': Property(
14670-
getValue: (CT_ c) => c.filePath,
14697+
'fileName': Property(
14698+
getValue: (CT_ c) => c.fileName,
1467114699
renderVariable:
1467214700
(CT_ c, Property<CT_> self, List<String> remainingNames) {
1467314701
if (remainingNames.isEmpty) {
@@ -14684,7 +14712,7 @@ class _Renderer_TopLevelVariable extends RendererBase<TopLevelVariable> {
1468414712
isNullValue: (CT_ c) => false,
1468514713
renderValue: (CT_ c, RendererBase<CT_> r,
1468614714
List<MustachioNode> ast, StringSink sink) {
14687-
_render_String(c.filePath, ast, r.template, sink,
14715+
_render_String(c.fileName, ast, r.template, sink,
1468814716
parent: r);
1468914717
},
1469014718
),
@@ -15360,8 +15388,8 @@ class _Renderer_Typedef extends RendererBase<Typedef> {
1536015388
parent: r);
1536115389
},
1536215390
),
15363-
'filePath': Property(
15364-
getValue: (CT_ c) => c.filePath,
15391+
'fileName': Property(
15392+
getValue: (CT_ c) => c.fileName,
1536515393
renderVariable:
1536615394
(CT_ c, Property<CT_> self, List<String> remainingNames) {
1536715395
if (remainingNames.isEmpty) {
@@ -15378,7 +15406,7 @@ class _Renderer_Typedef extends RendererBase<Typedef> {
1537815406
isNullValue: (CT_ c) => false,
1537915407
renderValue: (CT_ c, RendererBase<CT_> r,
1538015408
List<MustachioNode> ast, StringSink sink) {
15381-
_render_String(c.filePath, ast, r.template, sink,
15409+
_render_String(c.fileName, ast, r.template, sink,
1538215410
parent: r);
1538315411
},
1538415412
),

lib/src/model/container.dart

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,6 @@ abstract class Container extends ModelElement
232232
@override
233233
Iterable<CommentReferable> get referenceParents => [library];
234234

235-
@override
236-
String get filePath => '${canonicalLibraryOrThrow.dirName}/$fileName';
237-
238235
/// The full path of this element's sidebar file.
239236
String get sidebarPath;
240237

lib/src/model/enum.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ class Enum extends InheritingContainer with Constructable, MixedInTypes {
3131
...interfaceElements.expandInheritanceChain,
3232
];
3333

34+
@override
35+
// Prevent a collision with the library file.
36+
String get fileName => name == 'index' ? '$name-enum.html' : '$name.html';
37+
3438
@override
3539
String get sidebarPath =>
3640
'${canonicalLibraryOrThrow.dirName}/$name-enum-sidebar.html';

lib/src/model/library.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ class Library extends ModelElement
199199
String get filePath => '$dirName/$fileName';
200200

201201
@override
202-
String get fileName => '$dirName-library.html';
202+
String get fileName => 'index.html';
203203

204204
String get sidebarPath => '$dirName/$dirName-library-sidebar.html';
205205

@@ -216,9 +216,20 @@ class Library extends ModelElement
216216
if (!identical(canonicalModelElement, this)) {
217217
return canonicalModelElement?.href;
218218
}
219-
return '${package.baseHref}$filePath';
219+
// The file name for a library is 'index.html', so we just link to the
220+
// directory name. This keeps the URL looking short, _without_ the
221+
// 'index.html' in the URL.
222+
return '${package.baseHref}$dirName';
220223
}
221224

225+
/// The previous value of [filePath].
226+
///
227+
/// This path is used to write a file that ontains an HTML redirect (not an
228+
/// HTTP redirect) to a library's current [filePath].
229+
String get redirectingPath => '$dirName/$dirName-library.html';
230+
231+
/// Whether a libary is anonymous, either because it has no library directive
232+
/// or it has a library directive without a name.
222233
bool get isAnonymous => element.name.isEmpty;
223234

224235
@override

lib/src/model/model_element.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ abstract class ModelElement
615615

616616
/// The full path of the output file in which this element will be primarily
617617
/// documented.
618-
String get filePath;
618+
String get filePath => '${canonicalLibraryOrThrow.dirName}/$fileName';
619619

620620
@override
621621
String get fullyQualifiedName =>

lib/src/model/model_function.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ class ModelFunctionTyped extends ModelElement with TypeParameters {
4949
Library get enclosingElement => library;
5050

5151
@override
52-
String get filePath => '${canonicalLibrary?.dirName}/$fileName';
52+
// Prevent a collision with the library file.
53+
String get fileName => name == 'index' ? '$name-function.html' : '$name.html';
5354

5455
@override
5556
String get aboveSidebarPath => canonicalLibraryOrThrow.sidebarPath;

lib/src/model/package.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,13 @@ class Package extends LibraryContainer
136136
bool get isPublic =>
137137
_isLocalPublicByDefault || libraries.any((l) => l.isPublic);
138138

139-
/// Return true if this is the default package, this is part of an embedder
140-
/// SDK, or if [DartdocOptionContext.autoIncludeDependencies] is true -- but
141-
/// only if the package was not excluded on the command line.
139+
/// Whether this package is local.
140+
///
141+
/// A package can be local in three ways:
142+
/// * this is the default package,
143+
/// * this is part of an embedder SDK, or
144+
/// * [DartdocOptionContext.autoIncludeDependencies] is true, and this
145+
/// package is not excluded with `exclude-packages`.
142146
bool get isLocal {
143147
// Do not document as local if we excluded this package by name.
144148
if (_isExcluded) return false;

lib/src/model/top_level_variable.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class TopLevelVariable extends ModelElement
4343
Library get enclosingElement => library;
4444

4545
@override
46-
String get filePath => '${canonicalLibraryOrThrow.dirName}/$fileName';
46+
// Prevent a collision with the library file.
47+
String get fileName => name == 'index' ? '$name-property.html' : '$name.html';
4748

4849
@override
4950
String get aboveSidebarPath => canonicalLibraryOrThrow.sidebarPath;

lib/src/model/typedef.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ abstract class Typedef extends ModelElement
3333
String get linkedGenericParameters => _renderTypeParameters(isLinked: true);
3434

3535
@override
36-
String get filePath => '${canonicalLibraryOrThrow.dirName}/$fileName';
36+
// Prevent a collision with the library file.
37+
String get fileName => name == 'index' ? '$name-typedef.html' : '$name.html';
3738

3839
@override
3940
String get aboveSidebarPath => canonicalLibraryOrThrow.sidebarPath;

0 commit comments

Comments
 (0)