Skip to content

Extract fileName / fileType from ModelElement, LibraryContainer into FileStructure #3413

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 10 commits into from
May 12, 2023
137 changes: 79 additions & 58 deletions lib/src/generator/file_structure.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:dartdoc/src/model/model_element.dart';
import 'package:dartdoc/src/comment_references/parser.dart';
import 'package:dartdoc/src/failure.dart';
import 'package:meta/meta.dart';

const _html = 'html';
const _md = 'md';
import '../model/model.dart';

enum FileStructureMode {
htmlOriginal,
mdOriginal,
}
const _validFormats = {'html', 'md'};

/// This class defines an interface to allow [ModelElement]s and [Generator]s
/// to get information about the desired on-disk representation of a single
Expand All @@ -20,22 +18,58 @@ enum FileStructureMode {
/// to lay them out on disk, and how to link different pages in the structure
/// together.
abstract class FileStructure {
factory FileStructure(FileStructureMode mode, ModelElement modelElement) {
switch (mode) {
case FileStructureMode.htmlOriginal:
return _FileStructureHtml(modelElement);
case FileStructureMode.mdOriginal:
return _FileStructureMd(modelElement);
factory FileStructure.fromDocumentable(Documentable documentable) {
if (!_validFormats.contains(documentable.config.format)) {
throw DartdocFailure(
'Internal error: unrecognized config.format: ${documentable.config.format}');
}
switch (documentable) {
case LibraryContainer():
// [LibraryContainer]s are not ModelElements, but have documentation.
return FileStructure._fromLibraryContainer(documentable);
case ModelElement():
// This should be the common case.
return FileStructure._fromModelElement(documentable);
default:
throw UnimplementedError(
'Tried to build a FileStructure for an unknown subtype of Documentable: ${documentable.runtimeType}');
}
}

factory FileStructure._fromLibraryContainer(
LibraryContainer libraryContainer) {
final format = libraryContainer.config.format;
switch (libraryContainer) {
case Category():
return FileStructureImpl(format, libraryContainer.name, 'topic');
case Package():
return FileStructureImpl(format, 'index', null);
default:
throw UnimplementedError(
'Unrecognized LibraryContainer subtype: ${libraryContainer.runtimeType}');
}
}

/// Link to the [ModelElement] the information for this [FileStructure]
/// applies to.
// TODO(jcollins): consider not carrying a reference to a ModelElement and
// calculating necessary bits at construction time. Might be challenging
// if we want to calculate [hasIndependentFile] based on documentation
// length or other variables not always available.
ModelElement get modelElement;
factory FileStructure._fromModelElement(ModelElement modelElement) {
final format = modelElement.config.format;
switch (modelElement) {
case Library():
return FileStructureImpl(format, modelElement.dirName, 'library');
case Mixin():
return FileStructureImpl(format, modelElement.name, 'mixin');
case Class():
return FileStructureImpl(format, modelElement.name, 'class');
case Operator():
return FileStructureImpl(format,
'operator_${operatorNames[modelElement.referenceName]}', null);
case GetterSetterCombo():
return FileStructureImpl(format, modelElement.name,
modelElement.isConst ? 'constant' : null);
default:
return FileStructureImpl(
modelElement.config.format, modelElement.name, null);
}
}

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

class _FileStructureHtml implements FileStructure {
_FileStructureHtml(this.modelElement);

@override
// TODO: implement fileName
String get fileName => throw UnimplementedError();

@override
String get fileType => _html;

@override
// TODO: implement hasIndependentFile
bool get hasIndependentFile => throw UnimplementedError();

@override
// TODO: implement href
String get href => throw UnimplementedError();

@visibleForTesting
class FileStructureImpl implements FileStructure {
@override
// TODO: implement htmlId
String get htmlId => throw UnimplementedError();
final String fileType;

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

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind documenting what this field is?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not at all. It's kind of hacky so definitely deserves some description.


class _FileStructureMd implements FileStructure {
_FileStructureMd(this.modelElement);
FileStructureImpl(this.fileType, this.pathSafeName, this.kindAddition);

@override
// TODO: implement fileName
String get fileName => throw UnimplementedError();

@override
// TODO: implement fileType
String get fileType => _md;
/// Initial implementation is bug-for-bug compatible with pre-extraction
/// dartdoc. This means that some types will have kindAdditions, and
/// some will not. See [FileStructure._fromModelElement].
String get fileName {
if (kindAddition != null) {
return '$pathSafeName-$kindAddition.$fileType';
}
return '$pathSafeName.$fileType';
}

@override
// TODO: implement hasIndependentFile
bool get hasIndependentFile => throw UnimplementedError();
bool get hasIndependentFile => true;

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

@override
final ModelElement modelElement;

@override
// TODO: implement dirName
String get dirName => throw UnimplementedError();
Expand Down
Loading