Skip to content

Commit 0cf21c1

Browse files
authored
Extract fileName / fileType from ModelElement, LibraryContainer into FileStructure (#3413)
* intermediate * this is looking pretty good for fileName extraction * Finish up tests * Clean up accidental relative autoimport * Add comment and fix grind race condition (again?) * review comments, format * dartfmt * windows test failure?
1 parent 2ae78bc commit 0cf21c1

23 files changed

+290
-277
lines changed

lib/src/generator/file_structure.dart

Lines changed: 79 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'package:dartdoc/src/model/model_element.dart';
5+
import 'package:dartdoc/src/comment_references/parser.dart';
6+
import 'package:dartdoc/src/failure.dart';
7+
import 'package:meta/meta.dart';
68

7-
const _html = 'html';
8-
const _md = 'md';
9+
import '../model/model.dart';
910

10-
enum FileStructureMode {
11-
htmlOriginal,
12-
mdOriginal,
13-
}
11+
const _validFormats = {'html', 'md'};
1412

1513
/// This class defines an interface to allow [ModelElement]s and [Generator]s
1614
/// to get information about the desired on-disk representation of a single
@@ -20,22 +18,58 @@ enum FileStructureMode {
2018
/// to lay them out on disk, and how to link different pages in the structure
2119
/// together.
2220
abstract class FileStructure {
23-
factory FileStructure(FileStructureMode mode, ModelElement modelElement) {
24-
switch (mode) {
25-
case FileStructureMode.htmlOriginal:
26-
return _FileStructureHtml(modelElement);
27-
case FileStructureMode.mdOriginal:
28-
return _FileStructureMd(modelElement);
21+
factory FileStructure.fromDocumentable(Documentable documentable) {
22+
if (!_validFormats.contains(documentable.config.format)) {
23+
throw DartdocFailure(
24+
'Internal error: unrecognized config.format: ${documentable.config.format}');
25+
}
26+
switch (documentable) {
27+
case LibraryContainer():
28+
// [LibraryContainer]s are not ModelElements, but have documentation.
29+
return FileStructure._fromLibraryContainer(documentable);
30+
case ModelElement():
31+
// This should be the common case.
32+
return FileStructure._fromModelElement(documentable);
33+
default:
34+
throw UnimplementedError(
35+
'Tried to build a FileStructure for an unknown subtype of Documentable: ${documentable.runtimeType}');
36+
}
37+
}
38+
39+
factory FileStructure._fromLibraryContainer(
40+
LibraryContainer libraryContainer) {
41+
final format = libraryContainer.config.format;
42+
switch (libraryContainer) {
43+
case Category():
44+
return FileStructureImpl(format, libraryContainer.name, 'topic');
45+
case Package():
46+
return FileStructureImpl(format, 'index', null);
47+
default:
48+
throw UnimplementedError(
49+
'Unrecognized LibraryContainer subtype: ${libraryContainer.runtimeType}');
2950
}
3051
}
3152

32-
/// Link to the [ModelElement] the information for this [FileStructure]
33-
/// applies to.
34-
// TODO(jcollins): consider not carrying a reference to a ModelElement and
35-
// calculating necessary bits at construction time. Might be challenging
36-
// if we want to calculate [hasIndependentFile] based on documentation
37-
// length or other variables not always available.
38-
ModelElement get modelElement;
53+
factory FileStructure._fromModelElement(ModelElement modelElement) {
54+
final format = modelElement.config.format;
55+
switch (modelElement) {
56+
case Library():
57+
return FileStructureImpl(format, modelElement.dirName, 'library');
58+
case Mixin():
59+
return FileStructureImpl(format, modelElement.name, 'mixin');
60+
case Class():
61+
return FileStructureImpl(format, modelElement.name, 'class');
62+
case Operator():
63+
return FileStructureImpl(format,
64+
'operator_${operatorNames[modelElement.referenceName]}', null);
65+
case GetterSetterCombo():
66+
return FileStructureImpl(format, modelElement.name,
67+
modelElement.isConst ? 'constant' : null);
68+
default:
69+
return FileStructureImpl(
70+
modelElement.config.format, modelElement.name, null);
71+
}
72+
}
3973

4074
/// True if an independent file should be created for this `ModelElement`.
4175
bool get hasIndependentFile;
@@ -62,50 +96,40 @@ abstract class FileStructure {
6296
String get fileType;
6397
}
6498

65-
class _FileStructureHtml implements FileStructure {
66-
_FileStructureHtml(this.modelElement);
67-
68-
@override
69-
// TODO: implement fileName
70-
String get fileName => throw UnimplementedError();
71-
72-
@override
73-
String get fileType => _html;
74-
75-
@override
76-
// TODO: implement hasIndependentFile
77-
bool get hasIndependentFile => throw UnimplementedError();
78-
79-
@override
80-
// TODO: implement href
81-
String get href => throw UnimplementedError();
82-
99+
@visibleForTesting
100+
class FileStructureImpl implements FileStructure {
83101
@override
84-
// TODO: implement htmlId
85-
String get htmlId => throw UnimplementedError();
102+
final String fileType;
86103

87-
@override
88-
final ModelElement modelElement;
104+
/// This is a name for the underlying [Documentable] that is free of
105+
/// characters that can not appear in a path (URI, Unix, or Windows).
106+
String pathSafeName;
89107

90-
@override
91-
// TODO: implement dirName
92-
String get dirName => throw UnimplementedError();
93-
}
108+
/// This is a string to disambiguate the filename of the underlying
109+
/// [Documentable] from other files with the same [pathSafeName] in the
110+
/// same directory and is composed with [pathSafeName] to generate [fileName].
111+
/// It is usually based on [ModelElement.kind], e.g. `'class'`. If null, no
112+
/// disambiguating string will be added.
113+
// TODO(jcollins-g): Legacy layout doesn't always include this; move toward
114+
// always having a disambiguating string.
115+
final String? kindAddition;
94116

95-
class _FileStructureMd implements FileStructure {
96-
_FileStructureMd(this.modelElement);
117+
FileStructureImpl(this.fileType, this.pathSafeName, this.kindAddition);
97118

98119
@override
99-
// TODO: implement fileName
100-
String get fileName => throw UnimplementedError();
101120

102-
@override
103-
// TODO: implement fileType
104-
String get fileType => _md;
121+
/// Initial implementation is bug-for-bug compatible with pre-extraction
122+
/// dartdoc. This means that some types will have kindAdditions, and
123+
/// some will not. See [FileStructure._fromModelElement].
124+
String get fileName {
125+
if (kindAddition != null) {
126+
return '$pathSafeName-$kindAddition.$fileType';
127+
}
128+
return '$pathSafeName.$fileType';
129+
}
105130

106131
@override
107-
// TODO: implement hasIndependentFile
108-
bool get hasIndependentFile => throw UnimplementedError();
132+
bool get hasIndependentFile => true;
109133

110134
@override
111135
// TODO: implement href
@@ -115,9 +139,6 @@ class _FileStructureMd implements FileStructure {
115139
// TODO: implement htmlId
116140
String get htmlId => throw UnimplementedError();
117141

118-
@override
119-
final ModelElement modelElement;
120-
121142
@override
122143
// TODO: implement dirName
123144
String get dirName => throw UnimplementedError();

0 commit comments

Comments
 (0)