Skip to content

Commit 5156398

Browse files
authored
Fix sidebar links for pub packages (#3510)
1 parent 960bac4 commit 5156398

File tree

10 files changed

+1808
-1755
lines changed

10 files changed

+1808
-1755
lines changed

lib/resources/docs.dart.js

Lines changed: 1710 additions & 1690 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: 5 additions & 5 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: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,19 @@ abstract class GeneratorBackendBase implements GeneratorBackend {
141141

142142
/// Binds template data and emits the content to the [writer].
143143
void write(
144-
FileWriter writer, String filename, TemplateData data, String content) {
144+
FileWriter writer,
145+
String filename,
146+
TemplateData data,
147+
String content, {
148+
bool isSidebar = false,
149+
}) {
145150
if (!options.useBaseHref) {
146-
content = content.replaceAll(htmlBasePlaceholder, data.htmlBase);
151+
content = content.replaceAll(
152+
htmlBasePlaceholder,
153+
// URLs in sidebars are tweaked in the front-end; other URLs use
154+
// `htmlBase`.
155+
isSidebar ? '' : data.htmlBase,
156+
);
147157
}
148158
var element = data.self;
149159
writer.write(filename, content,

lib/src/generator/html_generator.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class HtmlGeneratorBackend extends GeneratorBackendBase {
4242
super.generateClass(packageGraph, library, clazz);
4343
var data = ClassTemplateData(options, packageGraph, library, clazz);
4444
var sidebarContent = templates.renderSidebarForContainer(data);
45-
write(writer, clazz.sidebarPath, data, sidebarContent);
45+
write(writer, clazz.sidebarPath, data, sidebarContent, isSidebar: true);
4646
runtimeStats.incrementAccumulator('writtenSidebarFileCount');
4747
}
4848

@@ -51,7 +51,7 @@ class HtmlGeneratorBackend extends GeneratorBackendBase {
5151
super.generateEnum(packageGraph, library, eNum);
5252
var data = EnumTemplateData(options, packageGraph, library, eNum);
5353
var sidebarContent = templates.renderSidebarForContainer(data);
54-
write(writer, eNum.sidebarPath, data, sidebarContent);
54+
write(writer, eNum.sidebarPath, data, sidebarContent, isSidebar: true);
5555
runtimeStats.incrementAccumulator('writtenSidebarFileCount');
5656
}
5757

@@ -61,7 +61,7 @@ class HtmlGeneratorBackend extends GeneratorBackendBase {
6161
super.generateExtension(packageGraph, library, extension);
6262
var data = ExtensionTemplateData(options, packageGraph, library, extension);
6363
var sidebarContent = templates.renderSidebarForContainer(data);
64-
write(writer, extension.sidebarPath, data, sidebarContent);
64+
write(writer, extension.sidebarPath, data, sidebarContent, isSidebar: true);
6565
runtimeStats.incrementAccumulator('writtenSidebarFileCount');
6666
}
6767

@@ -70,7 +70,7 @@ class HtmlGeneratorBackend extends GeneratorBackendBase {
7070
super.generateLibrary(packageGraph, library);
7171
var data = LibraryTemplateData(options, packageGraph, library);
7272
var sidebarContent = templates.renderSidebarForLibrary(data);
73-
write(writer, library.sidebarPath, data, sidebarContent);
73+
write(writer, library.sidebarPath, data, sidebarContent, isSidebar: true);
7474
runtimeStats.incrementAccumulator('writtenSidebarFileCount');
7575
}
7676

@@ -79,7 +79,7 @@ class HtmlGeneratorBackend extends GeneratorBackendBase {
7979
super.generateMixin(packageGraph, library, mixin);
8080
var data = MixinTemplateData(options, packageGraph, library, mixin);
8181
var sidebarContent = templates.renderSidebarForContainer(data);
82-
write(writer, mixin.sidebarPath, data, sidebarContent);
82+
write(writer, mixin.sidebarPath, data, sidebarContent, isSidebar: true);
8383
runtimeStats.incrementAccumulator('writtenSidebarFileCount');
8484
}
8585

test/templates/enum_test.dart

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -351,11 +351,10 @@ enum EnumWithDefaultConstructor {
351351
expect(
352352
enumWithDefaultConstructorRightSidebarLines,
353353
containsAllInOrder([
354-
matches(
355-
'<a href="../lib/EnumWithDefaultConstructor.html#constructors">'
354+
matches('<a href="lib/EnumWithDefaultConstructor.html#constructors">'
356355
'Constructors</a>'),
357356
matches(
358-
'<a href="../lib/EnumWithDefaultConstructor/EnumWithDefaultConstructor.html">'
357+
'<a href="lib/EnumWithDefaultConstructor/EnumWithDefaultConstructor.html">'
359358
'EnumWithDefaultConstructor</a>'),
360359
]),
361360
);
@@ -365,8 +364,8 @@ enum EnumWithDefaultConstructor {
365364
expect(
366365
eRightSidebarLines,
367366
containsAllInOrder([
368-
matches('<a href="../lib/E.html#constructors">Constructors</a>'),
369-
matches('<a href="../lib/E/E.named.html">named</a>'),
367+
matches('<a href="lib/E.html#constructors">Constructors</a>'),
368+
matches('<a href="lib/E/E.named.html">named</a>'),
370369
]),
371370
);
372371
});
@@ -375,8 +374,8 @@ enum EnumWithDefaultConstructor {
375374
expect(
376375
eRightSidebarLines,
377376
containsAllInOrder([
378-
matches('<a href="../lib/E.html#values">Values</a>'),
379-
matches('<li><a href="../lib/E.html#one">one</a></li>'),
377+
matches('<a href="lib/E.html#values">Values</a>'),
378+
matches('<li><a href="lib/E.html#one">one</a></li>'),
380379
]),
381380
);
382381
});
@@ -385,9 +384,9 @@ enum EnumWithDefaultConstructor {
385384
expect(
386385
eRightSidebarLines,
387386
containsAllInOrder([
388-
matches('<a href="../lib/E.html#instance-properties">Properties</a>'),
389-
matches('<a href="../lib/E/f1.html">f1</a>'),
390-
matches('<a href="../lib/E/index.html">index</a>'),
387+
matches('<a href="lib/E.html#instance-properties">Properties</a>'),
388+
matches('<a href="lib/E/f1.html">f1</a>'),
389+
matches('<a href="lib/E/index.html">index</a>'),
391390
]),
392391
);
393392
});
@@ -396,8 +395,8 @@ enum EnumWithDefaultConstructor {
396395
expect(
397396
eRightSidebarLines,
398397
containsAllInOrder([
399-
matches('<a href="../lib/E.html#instance-methods">Methods</a>'),
400-
matches('<a href="../lib/E/m1.html">m1</a>'),
398+
matches('<a href="lib/E.html#instance-methods">Methods</a>'),
399+
matches('<a href="lib/E/m1.html">m1</a>'),
401400
]),
402401
);
403402
});
@@ -406,8 +405,8 @@ enum EnumWithDefaultConstructor {
406405
expect(
407406
eRightSidebarLines,
408407
containsAllInOrder([
409-
matches('<a href="../lib/E.html#operators">Operators</a>'),
410-
matches('<a href="../lib/E/operator_greater.html">operator ></a>'),
408+
matches('<a href="lib/E.html#operators">Operators</a>'),
409+
matches('<a href="lib/E/operator_greater.html">operator ></a>'),
411410
]),
412411
);
413412
});
@@ -417,9 +416,9 @@ enum EnumWithDefaultConstructor {
417416
eRightSidebarLines,
418417
containsAllInOrder([
419418
matches(
420-
'<a href="../lib/E.html#static-properties">Static properties</a>'),
421-
matches('<a href="../lib/E/gs1.html">gs1</a>'),
422-
matches('<a href="../lib/E/sf1.html">sf1</a>'),
419+
'<a href="lib/E.html#static-properties">Static properties</a>'),
420+
matches('<a href="lib/E/gs1.html">gs1</a>'),
421+
matches('<a href="lib/E/sf1.html">sf1</a>'),
423422
]),
424423
);
425424
});
@@ -428,8 +427,8 @@ enum EnumWithDefaultConstructor {
428427
expect(
429428
eRightSidebarLines,
430429
containsAllInOrder([
431-
matches('<a href="../lib/E.html#static-methods">Static methods</a>'),
432-
matches('<a href="../lib/E/s1.html">s1</a>'),
430+
matches('<a href="lib/E.html#static-methods">Static methods</a>'),
431+
matches('<a href="lib/E/s1.html">s1</a>'),
433432
]),
434433
);
435434
});
@@ -438,9 +437,9 @@ enum EnumWithDefaultConstructor {
438437
expect(
439438
eRightSidebarLines,
440439
containsAllInOrder([
441-
matches('<a href="../lib/E.html#constants">Constants</a>'),
442-
matches('<a href="../lib/E/c1-constant.html">c1</a>'),
443-
matches('<a href="../lib/E/values-constant.html">values</a>'),
440+
matches('<a href="lib/E.html#constants">Constants</a>'),
441+
matches('<a href="lib/E/c1-constant.html">c1</a>'),
442+
matches('<a href="lib/E/values-constant.html">values</a>'),
444443
]),
445444
);
446445
});

test/templates/extension_test.dart

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ dartdoc:
141141
);
142142
});
143143

144-
test('enum page contains static methods', () async {
144+
test('extension page contains static methods', () async {
145145
expect(
146146
eLines,
147147
containsAllInOrder([
@@ -151,7 +151,7 @@ dartdoc:
151151
]));
152152
});
153153

154-
test('enum page contains static fields', () async {
154+
test('extension page contains static fields', () async {
155155
expect(
156156
eLines,
157157
containsAllInOrder([
@@ -161,7 +161,7 @@ dartdoc:
161161
]));
162162
});
163163

164-
test('enum page contains static getter/setter pairs', () async {
164+
test('extension page contains static getter/setter pairs', () async {
165165
expect(
166166
eLines,
167167
containsAllInOrder([
@@ -171,7 +171,7 @@ dartdoc:
171171
]));
172172
});
173173

174-
test('enum page contains (static) constants', () async {
174+
test('extension page contains (static) constants', () async {
175175
expect(
176176
eLines,
177177
containsAllInOrder([
@@ -181,7 +181,7 @@ dartdoc:
181181
]));
182182
});
183183

184-
test('enum page contains instance operators', () async {
184+
test('extension page contains instance operators', () async {
185185
expect(
186186
eLines,
187187
containsAllInOrder([
@@ -191,55 +191,55 @@ dartdoc:
191191
]));
192192
});
193193

194-
test('enum sidebar contains methods', () async {
194+
test('extension page contains source link', () async {
195195
expect(
196-
eRightSidebarLines,
196+
eLines,
197197
containsAllInOrder([
198-
matches('<a href="../lib/E.html#instance-methods">Methods</a>'),
199-
matches('<a href="../lib/E/m1.html">m1</a>'),
198+
matches('<a title="View source code" class="source-link" '
199+
'href="https://github.com/dart-lang/TEST_PKG/lib/lib.dart#L5">'
200+
'<span class="material-symbols-outlined">description</span></a>'),
200201
]),
201202
);
202203
});
203204

204-
test('enum sidebar contains operators', () async {
205+
test('extension sidebar contains methods', () async {
205206
expect(
206207
eRightSidebarLines,
207208
containsAllInOrder([
208-
matches('<a href="../lib/E.html#operators">Operators</a>'),
209-
matches('<a href="../lib/E/operator_greater.html">operator ></a>'),
209+
matches('<a href="lib/E.html#instance-methods">Methods</a>'),
210+
matches('<a href="lib/E/m1.html">m1</a>'),
210211
]),
211212
);
212213
});
213214

214-
test('enum sidebar contains static properties', () async {
215+
test('extension sidebar contains operators', () async {
215216
expect(
216217
eRightSidebarLines,
217218
containsAllInOrder([
218-
matches(
219-
'<a href="../lib/E.html#static-properties">Static properties</a>'),
220-
matches('<a href="../lib/E/gs1.html">gs1</a>'),
221-
matches('<a href="../lib/E/sf1.html">sf1</a>'),
219+
matches('<a href="lib/E.html#operators">Operators</a>'),
220+
matches('<a href="lib/E/operator_greater.html">operator ></a>'),
222221
]),
223222
);
224223
});
225224

226-
test('enum sidebar contains static methods', () async {
225+
test('extension sidebar contains static properties', () async {
227226
expect(
228227
eRightSidebarLines,
229228
containsAllInOrder([
230-
matches('<a href="../lib/E.html#static-methods">Static methods</a>'),
231-
matches('<a href="../lib/E/s1.html">s1</a>'),
229+
matches(
230+
'<a href="lib/E.html#static-properties">Static properties</a>'),
231+
matches('<a href="lib/E/gs1.html">gs1</a>'),
232+
matches('<a href="lib/E/sf1.html">sf1</a>'),
232233
]),
233234
);
234235
});
235236

236-
test('extension page contains source link', () async {
237+
test('extension sidebar contains static methods', () async {
237238
expect(
238-
eLines,
239+
eRightSidebarLines,
239240
containsAllInOrder([
240-
matches('<a title="View source code" class="source-link" '
241-
'href="https://github.com/dart-lang/TEST_PKG/lib/lib.dart#L5">'
242-
'<span class="material-symbols-outlined">description</span></a>'),
241+
matches('<a href="lib/E.html#static-methods">Static methods</a>'),
242+
matches('<a href="lib/E/s1.html">s1</a>'),
243243
]),
244244
);
245245
});

test/templates/field_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,15 @@ class B {
7272
.split('\n');
7373
});
7474

75-
test('method page contains method name', () async {
75+
test('field page contains method name', () async {
7676
f1Lines.expectMainContentContainsAllInOrder(
7777
[
7878
matches('<h1><span class="kind-property">f1</span> property'),
7979
],
8080
);
8181
});
8282

83-
test('enum page contains annotations', () async {
83+
test('field page contains annotations', () async {
8484
f1Lines.expectMainContentContainsAllInOrder(
8585
[
8686
matches('<ol class="annotation-list">'),

test/templates/method_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class B {
8080
);
8181
});
8282

83-
test('enum page contains annotations', () async {
83+
test('method page contains annotations', () async {
8484
m1Lines.expectMainContentContainsAllInOrder(
8585
[
8686
matches('<ol class="annotation-list">'),

web/docs.dart

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ void initializeSidebars() {
4141
}
4242
final aboveSidebarPath = mainContent.dataset['above-sidebar'];
4343
final leftSidebar = document.querySelector('#dartdoc-sidebar-left');
44+
final sanitizer = _SidebarNodeTreeSanitizer(baseHref);
4445
if (aboveSidebarPath != null &&
4546
aboveSidebarPath.isNotEmpty &&
4647
leftSidebar != null) {
4748
HttpRequest.getString('$baseHref$aboveSidebarPath').then((content) {
48-
leftSidebar.innerHtml = content;
49+
leftSidebar.setInnerHtml(content, treeSanitizer: sanitizer);
4950
});
5051
}
5152
final belowSidebarPath = mainContent.dataset['below-sidebar'];
@@ -54,7 +55,30 @@ void initializeSidebars() {
5455
belowSidebarPath.isNotEmpty &&
5556
rightSidebar != null) {
5657
HttpRequest.getString('$baseHref$belowSidebarPath').then((content) {
57-
rightSidebar.innerHtml = content;
58+
rightSidebar.setInnerHtml(content, treeSanitizer: sanitizer);
5859
});
5960
}
6061
}
62+
63+
/// A permissive sanitizer that allows external links (e.g. to api.dart.dev) and
64+
/// adjusts the links in a newly loaded sidebar, if "base href" is not being
65+
/// used.
66+
class _SidebarNodeTreeSanitizer implements NodeTreeSanitizer {
67+
final String baseHref;
68+
69+
_SidebarNodeTreeSanitizer(this.baseHref);
70+
71+
@override
72+
void sanitizeTree(Node node) {
73+
if (node is Element && node.nodeName == 'A') {
74+
final hrefString = node.attributes['href'];
75+
if (hrefString != null) {
76+
final href = Uri.parse(hrefString);
77+
if (!href.isAbsolute) {
78+
node.setAttribute('href', '$baseHref$hrefString');
79+
}
80+
}
81+
}
82+
node.childNodes.forEach(sanitizeTree);
83+
}
84+
}

web/sig.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
599BE3F0C7B0FCD52F532738D555B5AB
1+
9FB50EA3D9029CEDD3BEECB6D2431E1D

0 commit comments

Comments
 (0)