From 01f0843c5cf2ff4c6b1840f19eef496e45bbcbd8 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 11 May 2023 08:50:53 -0700 Subject: [PATCH 1/8] intermediate --- lib/src/generator/file_structure.dart | 22 +++++++++------------- lib/src/model/category.dart | 5 +++++ lib/src/model/documentable.dart | 3 +++ lib/src/model/model_element.dart | 5 +++++ lib/src/model/package.dart | 5 +++++ 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/lib/src/generator/file_structure.dart b/lib/src/generator/file_structure.dart index 03813b6f3d..ca8736d771 100644 --- a/lib/src/generator/file_structure.dart +++ b/lib/src/generator/file_structure.dart @@ -2,16 +2,12 @@ // 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/failure.dart'; import 'package:dartdoc/src/model/model_element.dart'; const _html = 'html'; const _md = 'md'; -enum FileStructureMode { - htmlOriginal, - mdOriginal, -} - /// This class defines an interface to allow [ModelElement]s and [Generator]s /// to get information about the desired on-disk representation of a single /// [ModelElement]. None of these getters should be considered valid unless @@ -20,12 +16,14 @@ 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: + factory FileStructure(String configFormat, ModelElement modelElement) { + switch(configFormat) { + case 'html': return _FileStructureHtml(modelElement); - case FileStructureMode.mdOriginal: + case 'md': return _FileStructureMd(modelElement); + default: + throw DartdocFailure('Internal error: unrecognized config.format: $configFormat'); } } @@ -73,8 +71,7 @@ class _FileStructureHtml implements FileStructure { String get fileType => _html; @override - // TODO: implement hasIndependentFile - bool get hasIndependentFile => throw UnimplementedError(); + bool get hasIndependentFile => true; @override // TODO: implement href @@ -104,8 +101,7 @@ class _FileStructureMd implements FileStructure { String get fileType => _md; @override - // TODO: implement hasIndependentFile - bool get hasIndependentFile => throw UnimplementedError(); + bool get hasIndependentFile => true; @override // TODO: implement href diff --git a/lib/src/model/category.dart b/lib/src/model/category.dart index c5cf534f70..bdc98943e4 100644 --- a/lib/src/model/category.dart +++ b/lib/src/model/category.dart @@ -5,6 +5,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; +import 'package:dartdoc/src/generator/file_structure.dart'; import 'package:dartdoc/src/model/comment_referable.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/model/model_object_builder.dart'; @@ -163,4 +164,8 @@ class Category extends Nameable @override // TODO: implement referenceParents Iterable get referenceParents => const []; + + @override + // TODO: implement fileStructure + FileStructure get fileStructure => FileStructure(config.format, null); } diff --git a/lib/src/model/documentable.dart b/lib/src/model/documentable.dart index 7075af566f..f7ba55375c 100644 --- a/lib/src/model/documentable.dart +++ b/lib/src/model/documentable.dart @@ -4,6 +4,7 @@ import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; +import 'package:dartdoc/src/generator/file_structure.dart'; import 'package:dartdoc/src/io_utils.dart'; import 'model.dart'; @@ -25,6 +26,8 @@ abstract class Documentable extends Nameable { DartdocOptionContext get config; + FileStructure get fileStructure; + String? get href; String get kind; diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index d28d00b792..51c0037031 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -15,6 +15,8 @@ import 'package:analyzer/src/dart/element/member.dart' show ExecutableMember, Member, ParameterMember; import 'package:collection/collection.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; +import 'package:dartdoc/src/failure.dart'; +import 'package:dartdoc/src/generator/file_structure.dart'; import 'package:dartdoc/src/model/annotation.dart'; import 'package:dartdoc/src/model/comment_referable.dart'; import 'package:dartdoc/src/model/feature.dart'; @@ -427,6 +429,9 @@ abstract class ModelElement extends Canonicalization .map((m) => Annotation(m, library, packageGraph)) .toList(growable: false); + @override + late final fileStructure = FileStructure(config.format, this); + @override late final bool isPublic = () { if (name.isEmpty) { diff --git a/lib/src/model/package.dart b/lib/src/model/package.dart index f61261a3b6..b4c2aec7d9 100644 --- a/lib/src/model/package.dart +++ b/lib/src/model/package.dart @@ -4,6 +4,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; +import 'package:dartdoc/src/generator/file_structure.dart'; import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/model/comment_referable.dart'; import 'package:dartdoc/src/model/model.dart'; @@ -417,4 +418,8 @@ class Package extends LibraryContainer @override String get referenceName => 'package:$name'; + + @override + // TODO: implement fileStructure + FileStructure get fileStructure => FileStructure(config.format, null); } From 40e613b1fb0611ae0f1ce64a8361e070b762a830 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 11 May 2023 14:16:30 -0700 Subject: [PATCH 2/8] this is looking pretty good for fileName extraction --- lib/src/generator/file_structure.dart | 144 ++++++++----- .../templates.runtime_renderers.dart | 201 +++++------------- lib/src/model/category.dart | 11 +- lib/src/model/class.dart | 3 - lib/src/model/constructor.dart | 2 +- lib/src/model/container.dart | 2 +- lib/src/model/enum.dart | 2 +- lib/src/model/extension.dart | 2 +- lib/src/model/field.dart | 5 +- lib/src/model/library.dart | 5 +- lib/src/model/library_container.dart | 8 +- lib/src/model/method.dart | 2 +- lib/src/model/mixin.dart | 3 - lib/src/model/model_element.dart | 13 +- lib/src/model/model_function.dart | 2 +- lib/src/model/operator.dart | 10 - lib/src/model/package.dart | 5 - lib/src/model/top_level_variable.dart | 5 +- lib/src/model/typedef.dart | 2 +- test/end2end/model_test.dart | 25 +++ test/generator/file_structure_test.dart | 10 +- 21 files changed, 194 insertions(+), 268 deletions(-) diff --git a/lib/src/generator/file_structure.dart b/lib/src/generator/file_structure.dart index ca8736d771..d808bb9a97 100644 --- a/lib/src/generator/file_structure.dart +++ b/lib/src/generator/file_structure.dart @@ -2,11 +2,22 @@ // 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/comment_references/parser.dart'; import 'package:dartdoc/src/failure.dart'; +import 'package:dartdoc/src/model/category.dart'; +import 'package:dartdoc/src/model/class.dart'; +import 'package:dartdoc/src/model/documentable.dart'; +import 'package:dartdoc/src/model/getter_setter_combo.dart'; +import 'package:dartdoc/src/model/library.dart'; +import 'package:dartdoc/src/model/library_container.dart'; import 'package:dartdoc/src/model/model_element.dart'; +import 'package:dartdoc/src/model/operator.dart'; +import 'package:dartdoc/src/model/package.dart'; +import 'package:meta/meta.dart'; -const _html = 'html'; -const _md = 'md'; +import '../model/mixin.dart'; + +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 @@ -16,24 +27,70 @@ const _md = 'md'; /// to lay them out on disk, and how to link different pages in the structure /// together. abstract class FileStructure { - factory FileStructure(String configFormat, ModelElement modelElement) { - switch(configFormat) { - case 'html': - return _FileStructureHtml(modelElement); - case 'md': - 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) { + String? kindAddition; + String? pathSafeName = libraryContainer.name; + switch(libraryContainer) { + case Category(): + kindAddition = 'topic'; + break; + case Package(): + pathSafeName = 'index'; + break; default: - throw DartdocFailure('Internal error: unrecognized config.format: $configFormat'); + throw UnimplementedError('Unrecognized LibraryContainer subtype: ${libraryContainer.runtimeType}'); } + + return FileStructureImpl(libraryContainer.config.format, pathSafeName, kindAddition); } - /// 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) { + String? kindAddition; + String? pathSafeName = modelElement.name; + switch(modelElement) { + case Library(): + kindAddition = 'library'; + pathSafeName = modelElement.dirName; + break; + case Mixin(): + kindAddition = 'mixin'; + break; + case Class(): + kindAddition = 'class'; + break; + case Operator(): + var referenceName = modelElement.referenceName; + if (operatorNames.containsKey(referenceName)) { + pathSafeName = 'operator_${operatorNames[referenceName]}'; + } + break; + case GetterSetterCombo(): + if (modelElement.isConst) { + kindAddition = 'constant'; + } + break; + default: + break; + } + + return FileStructureImpl(modelElement.config.format, pathSafeName, kindAddition); + } /// True if an independent file should be created for this `ModelElement`. bool get hasIndependentFile; @@ -60,45 +117,25 @@ 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; - +@visibleForTesting +class FileStructureImpl implements FileStructure { @override - bool get hasIndependentFile => true; + final String fileType; + String pathSafeName; + final String? kindAddition; - @override - // TODO: implement href - String get href => throw UnimplementedError(); + FileStructureImpl(this.fileType, this.pathSafeName, this.kindAddition); @override - // TODO: implement htmlId - String get htmlId => throw UnimplementedError(); - - @override - final ModelElement modelElement; - - @override - // TODO: implement dirName - String get dirName => throw UnimplementedError(); -} - -class _FileStructureMd implements FileStructure { - _FileStructureMd(this.modelElement); - - @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 bool get hasIndependentFile => true; @@ -111,10 +148,7 @@ 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(); -} +} \ No newline at end of file diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index f6308a001b..4dd6434bc4 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -1684,28 +1684,6 @@ class _Renderer_Class extends RendererBase { parent: r, getters: _invisibleGetters['ClassElement']!); }, ), - 'fileName': Property( - getValue: (CT_ c) => c.fileName, - renderVariable: - (CT_ c, Property self, List 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 r, - List ast, StringSink sink) { - _render_String(c.fileName, ast, r.template, sink, - parent: r); - }, - ), 'inheritanceChain': Property( getValue: (CT_ c) => c.inheritanceChain, renderVariable: (CT_ c, Property self, @@ -3800,6 +3778,20 @@ class _Renderer_Documentable extends RendererBase { parent: r); }, ), + 'fileStructure': Property( + getValue: (CT_ c) => c.fileStructure, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable( + c, remainingNames, 'FileStructure'), + isNullValue: (CT_ c) => false, + renderValue: (CT_ c, RendererBase r, + List ast, StringSink sink) { + renderSimple(c.fileStructure, ast, r.template, sink, + parent: r, + getters: _invisibleGetters['FileStructure']!); + }, + ), 'hasDocumentation': Property( getValue: (CT_ c) => c.hasDocumentation, renderVariable: (CT_ c, Property self, @@ -5494,28 +5486,6 @@ class _Renderer_Field extends RendererBase { parent: r, getters: _invisibleGetters['FieldElement']!); }, ), - 'fileName': Property( - getValue: (CT_ c) => c.fileName, - renderVariable: - (CT_ c, Property self, List 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 r, - List ast, StringSink sink) { - _render_String(c.fileName, ast, r.template, sink, - parent: r); - }, - ), 'filePath': Property( getValue: (CT_ c) => c.filePath, renderVariable: @@ -7911,28 +7881,6 @@ class _Renderer_Library extends RendererBase { _render_Extension(e, ast, r.template, sink, parent: r)); }, ), - 'fileName': Property( - getValue: (CT_ c) => c.fileName, - renderVariable: - (CT_ c, Property self, List 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 r, - List ast, StringSink sink) { - _render_String(c.fileName, ast, r.template, sink, - parent: r); - }, - ), 'filePath': Property( getValue: (CT_ c) => c.filePath, renderVariable: @@ -8353,6 +8301,20 @@ class _Renderer_LibraryContainer extends RendererBase { parent: r); }, ), + 'fileStructure': Property( + getValue: (CT_ c) => c.fileStructure, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable( + c, remainingNames, 'FileStructure'), + isNullValue: (CT_ c) => false, + renderValue: (CT_ c, RendererBase r, + List ast, StringSink sink) { + renderSimple(c.fileStructure, ast, r.template, sink, + parent: r, + getters: _invisibleGetters['FileStructure']!); + }, + ), 'hasPublicLibraries': Property( getValue: (CT_ c) => c.hasPublicLibraries, renderVariable: (CT_ c, Property self, @@ -8379,19 +8341,6 @@ class _Renderer_LibraryContainer extends RendererBase { _render_Library(e, ast, r.template, sink, parent: r)); }, ), - 'packageGraph': Property( - getValue: (CT_ c) => c.packageGraph, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable( - c, remainingNames, 'PackageGraph'), - isNullValue: (CT_ c) => false, - renderValue: (CT_ c, RendererBase r, - List ast, StringSink sink) { - renderSimple(c.packageGraph, ast, r.template, sink, - parent: r, getters: _invisibleGetters['PackageGraph']!); - }, - ), 'publicLibraries': Property( getValue: (CT_ c) => c.publicLibraries, renderVariable: (CT_ c, Property self, @@ -9525,28 +9474,6 @@ class _Renderer_Mixin extends RendererBase { parent: r, getters: _invisibleGetters['MixinElement']!); }, ), - 'fileName': Property( - getValue: (CT_ c) => c.fileName, - renderVariable: - (CT_ c, Property self, List 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 r, - List ast, StringSink sink) { - _render_String(c.fileName, ast, r.template, sink, - parent: r); - }, - ), 'hasModifiers': Property( getValue: (CT_ c) => c.hasModifiers, renderVariable: (CT_ c, Property self, @@ -10139,6 +10066,20 @@ class _Renderer_ModelElement extends RendererBase { parent: r); }, ), + 'fileStructure': Property( + getValue: (CT_ c) => c.fileStructure, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable( + c, remainingNames, 'FileStructure'), + isNullValue: (CT_ c) => false, + renderValue: (CT_ c, RendererBase r, + List ast, StringSink sink) { + renderSimple(c.fileStructure, ast, r.template, sink, + parent: r, + getters: _invisibleGetters['FileStructure']!); + }, + ), 'fileType': Property( getValue: (CT_ c) => c.fileType, renderVariable: @@ -11297,28 +11238,6 @@ class _Renderer_Operator extends RendererBase { CT_, () => { ..._Renderer_Method.propertyMap(), - 'fileName': Property( - getValue: (CT_ c) => c.fileName, - renderVariable: - (CT_ c, Property self, List 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 r, - List ast, StringSink sink) { - _render_String(c.fileName, ast, r.template, sink, - parent: r); - }, - ), 'fullyQualifiedName': Property( getValue: (CT_ c) => c.fullyQualifiedName, renderVariable: @@ -12406,13 +12325,13 @@ class _Renderer_PackageTemplateData extends RendererBase { } } -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(); } -String renderError(PackageTemplateData context, Template template) { +String renderSearchPage(PackageTemplateData context, Template template) { var buffer = StringBuffer(); _render_PackageTemplateData(context, template.ast, template, buffer); return buffer.toString(); @@ -14546,28 +14465,6 @@ class _Renderer_TopLevelVariable extends RendererBase { parent: r, getters: _invisibleGetters['Feature']!)); }, ), - 'fileName': Property( - getValue: (CT_ c) => c.fileName, - renderVariable: - (CT_ c, Property self, List 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 r, - List ast, StringSink sink) { - _render_String(c.fileName, ast, r.template, sink, - parent: r); - }, - ), 'filePath': Property( getValue: (CT_ c) => c.filePath, renderVariable: @@ -16196,6 +16093,16 @@ const _invisibleGetters = { 'modificationStamp', 'runtimeType' }, + 'FileStructure': { + 'dirName', + 'fileName', + 'fileType', + 'hasIndependentFile', + 'hashCode', + 'href', + 'htmlId', + 'runtimeType' + }, 'FunctionElement': { 'hashCode', 'isDartCoreIdentical', diff --git a/lib/src/model/category.dart b/lib/src/model/category.dart index bdc98943e4..232c6f74c1 100644 --- a/lib/src/model/category.dart +++ b/lib/src/model/category.dart @@ -5,7 +5,6 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; -import 'package:dartdoc/src/generator/file_structure.dart'; import 'package:dartdoc/src/model/comment_referable.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/model/model_object_builder.dart'; @@ -93,9 +92,7 @@ class Category extends Nameable @override String get fullyQualifiedName => name; - String get _fileType => package.fileType; - - String get filePath => 'topics/$name-topic.$_fileType'; + String get filePath => 'topics/${fileStructure.fileName}'; @override String? get href => isCanonical ? '${package.baseHref}$filePath' : null; @@ -158,14 +155,8 @@ class Category extends Nameable packageGraph.rendererFactory.categoryRenderer; @override - // TODO: implement referenceChildren Map get referenceChildren => const {}; @override - // TODO: implement referenceParents Iterable get referenceParents => const []; - - @override - // TODO: implement fileStructure - FileStructure get fileStructure => FileStructure(config.format, null); } diff --git a/lib/src/model/class.dart b/lib/src/model/class.dart index 5bfe933c53..6e9d8ec2c1 100644 --- a/lib/src/model/class.dart +++ b/lib/src/model/class.dart @@ -44,9 +44,6 @@ class Class extends InheritingContainer packageGraph.specialClasses.addSpecial(this); } - @override - String get fileName => '$name-class.$fileType'; - @override bool get isAbstract => element.isAbstract; diff --git a/lib/src/model/constructor.dart b/lib/src/model/constructor.dart index 0cf9f73cae..73553469e4 100644 --- a/lib/src/model/constructor.dart +++ b/lib/src/model/constructor.dart @@ -37,7 +37,7 @@ class Constructor extends ModelElement @override String get filePath => - '${enclosingElement.library.dirName}/${enclosingElement.name}/$fileName'; + '${enclosingElement.library.dirName}/${enclosingElement.name}/${fileStructure.fileName}'; String get fullKind { if (isConst) return 'const $kind'; diff --git a/lib/src/model/container.dart b/lib/src/model/container.dart index eba4fe5dda..4e40232fe2 100644 --- a/lib/src/model/container.dart +++ b/lib/src/model/container.dart @@ -266,7 +266,7 @@ abstract class Container extends ModelElement Iterable get referenceParents => [definingLibrary, library]; @override - String get filePath => '${library.dirName}/$fileName'; + String get filePath => '${library.dirName}/${fileStructure.fileName}'; /// The CSS class to use in an inheritance list. String get relationshipsClass; diff --git a/lib/src/model/enum.dart b/lib/src/model/enum.dart index 93943332ef..0154b7c355 100644 --- a/lib/src/model/enum.dart +++ b/lib/src/model/enum.dart @@ -113,7 +113,7 @@ class EnumField extends Field { assert(!(canonicalLibrary == null || canonicalEnclosingContainer == null)); assert(canonicalLibrary == library); assert(canonicalEnclosingContainer == enclosingElement); - return '${package.baseHref}${enclosingElement.library.dirName}/${enclosingElement.fileName}'; + return '${package.baseHref}${enclosingElement.library.dirName}/${enclosingElement.fileStructure.fileName}'; } @override diff --git a/lib/src/model/extension.dart b/lib/src/model/extension.dart index 3ea4ccff01..b15a8af000 100644 --- a/lib/src/model/extension.dart +++ b/lib/src/model/extension.dart @@ -93,7 +93,7 @@ class Extension extends Container implements EnclosedElement { ]; @override - String get filePath => '${library.dirName}/$fileName'; + String get filePath => '${library.dirName}/${fileStructure.fileName}'; Map? _referenceChildren; @override diff --git a/lib/src/model/field.dart b/lib/src/model/field.dart index 051d2790e0..bf6eae90c5 100644 --- a/lib/src/model/field.dart +++ b/lib/src/model/field.dart @@ -71,7 +71,7 @@ class Field extends ModelElement @override String get filePath => - '${enclosingElement.library.dirName}/${enclosingElement.name}/$fileName'; + '${enclosingElement.library.dirName}/${enclosingElement.name}/${fileStructure.fileName}'; @override String? get href { @@ -143,9 +143,6 @@ class Field extends ModelElement @Deprecated('Use `element`') FieldElement? get field => element; - @override - String get fileName => '${isConst ? '$name-constant' : name}.$fileType'; - SourceCodeRenderer get _sourceCodeRenderer => packageGraph.rendererFactory.sourceCodeRenderer; diff --git a/lib/src/model/library.dart b/lib/src/model/library.dart index fd38275e38..f44bbc61d5 100644 --- a/lib/src/model/library.dart +++ b/lib/src/model/library.dart @@ -331,10 +331,7 @@ class Library extends ModelElement allClasses.where((c) => c.isErrorOrException).toList(growable: false); @override - String get fileName => '$dirName-library.$fileType'; - - @override - String get filePath => '${library.dirName}/$fileName'; + String get filePath => '${library.dirName}/${fileStructure.fileName}'; @override late final List functions = diff --git a/lib/src/model/library_container.dart b/lib/src/model/library_container.dart index 64aa1e5306..3dc6758c52 100644 --- a/lib/src/model/library_container.dart +++ b/lib/src/model/library_container.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:collection/collection.dart'; +import 'package:dartdoc/src/generator/file_structure.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/model_utils.dart' as model_utils; @@ -11,11 +12,9 @@ import 'package:dartdoc/src/model_utils.dart' as model_utils; /// Do not cache return values of any methods or members excepting [libraries] /// and [name] before finishing initialization of a [LibraryContainer]. abstract mixin class LibraryContainer - implements Nameable, Comparable { + implements Nameable, Comparable, Documentable { final List libraries = []; - PackageGraph get packageGraph; - Iterable get publicLibraries => model_utils.filterNonPublic(libraries); @@ -64,4 +63,7 @@ abstract mixin class LibraryContainer } return Comparable.compare(_group, other._group); } + + @override + late final FileStructure fileStructure = FileStructure.fromDocumentable(this); } diff --git a/lib/src/model/method.dart b/lib/src/model/method.dart index b057d3a5b6..68603197c7 100644 --- a/lib/src/model/method.dart +++ b/lib/src/model/method.dart @@ -62,7 +62,7 @@ class Method extends ModelElement @override String get filePath => - '${enclosingElement.library.dirName}/${enclosingElement.name}/$fileName'; + '${enclosingElement.library.dirName}/${enclosingElement.name}/${fileStructure.fileName}'; String get fullkind { // A method cannot be abstract and static at the same time. diff --git a/lib/src/model/mixin.dart b/lib/src/model/mixin.dart index 31d78803d1..5e07215ef9 100644 --- a/lib/src/model/mixin.dart +++ b/lib/src/model/mixin.dart @@ -45,9 +45,6 @@ class Mixin extends InheritingContainer with TypeImplementing { Iterable> get extraReferenceChildren => const []; - @override - String get fileName => '$name-mixin.$fileType'; - @override bool get hasModifiers => super.hasModifiers || hasPublicSuperclassConstraints; diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index 51c0037031..571a01cfd2 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -15,7 +15,6 @@ import 'package:analyzer/src/dart/element/member.dart' show ExecutableMember, Member, ParameterMember; import 'package:collection/collection.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; -import 'package:dartdoc/src/failure.dart'; import 'package:dartdoc/src/generator/file_structure.dart'; import 'package:dartdoc/src/model/annotation.dart'; import 'package:dartdoc/src/model/comment_referable.dart'; @@ -429,9 +428,6 @@ abstract class ModelElement extends Canonicalization .map((m) => Annotation(m, library, packageGraph)) .toList(growable: false); - @override - late final fileStructure = FileStructure(config.format, this); - @override late final bool isPublic = () { if (name.isEmpty) { @@ -644,9 +640,11 @@ abstract class ModelElement extends Canonicalization return '($sourceUri)'; } - String get fileName => '$name.$fileType'; + @Deprecated('replace with fileStructure.fileName') + String get fileName => fileStructure.fileName; - String get fileType => package.fileType; + @Deprecated('replace with fileStructure.fileType') + String get fileType => fileStructure.fileType; String get filePath; @@ -907,4 +905,7 @@ abstract class ModelElement extends Canonicalization } String get linkedObjectType => _packageGraph.dartCoreObject; + + @override + late final FileStructure fileStructure = FileStructure.fromDocumentable(this); } diff --git a/lib/src/model/model_function.dart b/lib/src/model/model_function.dart index 7f34bc00b1..7aa1fef29e 100644 --- a/lib/src/model/model_function.dart +++ b/lib/src/model/model_function.dart @@ -52,7 +52,7 @@ class ModelFunctionTyped extends ModelElement ModelElement get enclosingElement => library; @override - String get filePath => '${library.dirName}/$fileName'; + String get filePath => '${library.dirName}/${fileStructure.fileName}'; @override String? get href { diff --git a/lib/src/model/operator.dart b/lib/src/model/operator.dart index f2b438df35..0fb87ea956 100644 --- a/lib/src/model/operator.dart +++ b/lib/src/model/operator.dart @@ -5,7 +5,6 @@ // ignore: implementation_imports import 'package:analyzer/src/dart/element/member.dart' show ExecutableMember, Member; -import 'package:dartdoc/src/comment_references/parser.dart'; import 'package:dartdoc/src/model/model.dart'; class Operator extends Method { @@ -16,15 +15,6 @@ class Operator extends Method { {Member? originalMember}) : super.inherited(originalMember: originalMember as ExecutableMember?); - @override - String get fileName { - var actualName = super.name; - if (operatorNames.containsKey(actualName)) { - actualName = 'operator_${operatorNames[actualName]}'; - } - return '$actualName.$fileType'; - } - @override String get fullyQualifiedName => '${library.name}.${enclosingElement.name}.${super.name}'; diff --git a/lib/src/model/package.dart b/lib/src/model/package.dart index b4c2aec7d9..f61261a3b6 100644 --- a/lib/src/model/package.dart +++ b/lib/src/model/package.dart @@ -4,7 +4,6 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; -import 'package:dartdoc/src/generator/file_structure.dart'; import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/model/comment_referable.dart'; import 'package:dartdoc/src/model/model.dart'; @@ -418,8 +417,4 @@ class Package extends LibraryContainer @override String get referenceName => 'package:$name'; - - @override - // TODO: implement fileStructure - FileStructure get fileStructure => FileStructure(config.format, null); } diff --git a/lib/src/model/top_level_variable.dart b/lib/src/model/top_level_variable.dart index d80e6d0a46..d9be3b4b07 100644 --- a/lib/src/model/top_level_variable.dart +++ b/lib/src/model/top_level_variable.dart @@ -43,7 +43,7 @@ class TopLevelVariable extends ModelElement ModelElement get enclosingElement => library; @override - String get filePath => '${library.dirName}/$fileName'; + String get filePath => '${library.dirName}/${fileStructure.fileName}'; @override String? get href { @@ -75,9 +75,6 @@ class TopLevelVariable extends ModelElement @override Set get features => {...super.features, ...comboFeatures}; - @override - String get fileName => '${isConst ? '$name-constant' : name}.$fileType'; - @override Iterable get referenceParents => [definingLibrary]; diff --git a/lib/src/model/typedef.dart b/lib/src/model/typedef.dart index 7490d4da8e..f8d189b9f0 100644 --- a/lib/src/model/typedef.dart +++ b/lib/src/model/typedef.dart @@ -36,7 +36,7 @@ abstract class Typedef extends ModelElement _renderer.renderLinkedGenericParameters(this); @override - String get filePath => '${library.dirName}/$fileName'; + String get filePath => '${library.dirName}/${fileStructure.fileName}'; /// Helper for mustache templates, which can't do casting themselves /// without this. diff --git a/test/end2end/model_test.dart b/test/end2end/model_test.dart index 2e27dd69be..d10a3ceff7 100644 --- a/test/end2end/model_test.dart +++ b/test/end2end/model_test.dart @@ -11,6 +11,7 @@ import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/source/line_info.dart'; import 'package:async/async.dart'; import 'package:collection/src/iterable_extensions.dart'; +import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/element_type.dart'; import 'package:dartdoc/src/matching_link_result.dart'; import 'package:dartdoc/src/model/feature.dart'; @@ -51,6 +52,30 @@ class TestLibraryContainer extends LibraryContainer with Nameable { TestLibraryContainer( this.name, this.containerOrder, LibraryContainer? enclosingContainer) : enclosingName = enclosingContainer?.name ?? ''; + + @override + DartdocOptionContext get config => throw UnimplementedError(); + + @override + String? get documentation => throw UnimplementedError(); + + @override + String get documentationAsHtml => throw UnimplementedError(); + + @override + bool get hasDocumentation => throw UnimplementedError(); + + @override + String? get href => throw UnimplementedError(); + + @override + bool get isDocumented => throw UnimplementedError(); + + @override + String get kind => throw UnimplementedError(); + + @override + String get oneLineDoc => throw UnimplementedError(); } class TestLibraryContainerSdk extends TestLibraryContainer { diff --git a/test/generator/file_structure_test.dart b/test/generator/file_structure_test.dart index 9e2463f512..7656d3e73f 100644 --- a/test/generator/file_structure_test.dart +++ b/test/generator/file_structure_test.dart @@ -2,7 +2,6 @@ // 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/generator/file_structure.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; @@ -20,15 +19,12 @@ class FileStructureTest extends DartdocTestBase { @override String get libraryName => 'file_structure_test'; - void test_createFileStructureForVariable() async { + void test_fileNamesForModelElements() async { var library = await bootPackageWithLibrary(''' var globalVar = 123; '''); var globalVar = library.properties.named('globalVar'); - var htmlStructure = - FileStructure(FileStructureMode.htmlOriginal, globalVar); - var mdStructure = FileStructure(FileStructureMode.mdOriginal, globalVar); - expect(htmlStructure.fileType, equals('html')); - expect(mdStructure.fileType, equals('md')); + var structure = globalVar.fileStructure; + expect(structure.fileName, equals('globalVar.html')); } } From 85aea33a0dd87919df8e338233f2d857aa87aa22 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Fri, 12 May 2023 10:45:16 -0700 Subject: [PATCH 3/8] Finish up tests --- lib/src/generator/file_structure.dart | 27 +++++---- test/dartdoc_test_base.dart | 80 +++++++++++++------------ test/generator/file_structure_test.dart | 52 +++++++++++++++- 3 files changed, 109 insertions(+), 50 deletions(-) diff --git a/lib/src/generator/file_structure.dart b/lib/src/generator/file_structure.dart index d808bb9a97..47bfcc57b7 100644 --- a/lib/src/generator/file_structure.dart +++ b/lib/src/generator/file_structure.dart @@ -29,24 +29,27 @@ const _validFormats = {'html', 'md'}; abstract class FileStructure { factory FileStructure.fromDocumentable(Documentable documentable) { if (!_validFormats.contains(documentable.config.format)) { - throw DartdocFailure('Internal error: unrecognized config.format: ${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. + // [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}'); + throw UnimplementedError( + 'Tried to build a FileStructure for an unknown subtype of Documentable: ${documentable.runtimeType}'); } } - factory FileStructure._fromLibraryContainer(LibraryContainer libraryContainer) { + factory FileStructure._fromLibraryContainer( + LibraryContainer libraryContainer) { String? kindAddition; String? pathSafeName = libraryContainer.name; - switch(libraryContainer) { + switch (libraryContainer) { case Category(): kindAddition = 'topic'; break; @@ -54,16 +57,18 @@ abstract class FileStructure { pathSafeName = 'index'; break; default: - throw UnimplementedError('Unrecognized LibraryContainer subtype: ${libraryContainer.runtimeType}'); + throw UnimplementedError( + 'Unrecognized LibraryContainer subtype: ${libraryContainer.runtimeType}'); } - return FileStructureImpl(libraryContainer.config.format, pathSafeName, kindAddition); + return FileStructureImpl( + libraryContainer.config.format, pathSafeName, kindAddition); } factory FileStructure._fromModelElement(ModelElement modelElement) { String? kindAddition; String? pathSafeName = modelElement.name; - switch(modelElement) { + switch (modelElement) { case Library(): kindAddition = 'library'; pathSafeName = modelElement.dirName; @@ -89,7 +94,8 @@ abstract class FileStructure { break; } - return FileStructureImpl(modelElement.config.format, pathSafeName, kindAddition); + return FileStructureImpl( + modelElement.config.format, pathSafeName, kindAddition); } /// True if an independent file should be created for this `ModelElement`. @@ -127,6 +133,7 @@ class FileStructureImpl implements FileStructure { FileStructureImpl(this.fileType, this.pathSafeName, this.kindAddition); @override + /// 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]. @@ -151,4 +158,4 @@ class FileStructureImpl implements FileStructure { @override // TODO: implement dirName String get dirName => throw UnimplementedError(); -} \ No newline at end of file +} diff --git a/test/dartdoc_test_base.dart b/test/dartdoc_test_base.dart index aa18c6eaad..ef89bc9b6a 100644 --- a/test/dartdoc_test_base.dart +++ b/test/dartdoc_test_base.dart @@ -11,6 +11,8 @@ import 'package:meta/meta.dart'; import 'src/test_descriptor_utils.dart' as d; import 'src/utils.dart'; +typedef FileGenerator = Iterable Function(); + /// Exception thrown for invalid use of [DartdocTestBase]'s api. class DartdocTestBaseFailure implements Exception { final String message; @@ -70,23 +72,37 @@ analyzer: packagePath, name, Uri.file('$packagePath/')); } + Future _bootPackageFromFiles(FileGenerator files) async { + var packagePathBasename = + resourceProvider.pathContext.basename(packagePath); + var packagePathDirname = resourceProvider.pathContext.dirname(packagePath); + await d + .dir(packagePathBasename, files()) + .createInMemory(resourceProvider, packagePathDirname); + return await bootBasicPackage( + packagePath, + packageMetaProvider, + packageConfigProvider, + ); + } + + /// Creates a single library named [libraryName], with optional preamble + /// [libraryPreamble]. Optionally, pass a [FileGenerator] to create + /// extra files in the package such as `dartdoc_options.yaml`. Future bootPackageWithLibrary(String libraryContent, - {String libraryPreamble = ''}) async { - await d.dir('lib', [ - d.file('lib.dart', ''' + {String libraryPreamble = '', FileGenerator? extraFiles}) async { + return (await _bootPackageFromFiles(() => [ + d.dir('lib', [ + d.file('lib.dart', ''' $libraryPreamble library $libraryName; $libraryContent '''), - ]).createInMemory(resourceProvider, packagePath); - - var packageGraph = await bootBasicPackage( - packagePath, - packageMetaProvider, - packageConfigProvider, - ); - return packageGraph.libraries.named(libraryName); + ]), + ])) + .libraries + .named(libraryName); } /// Similar to [bootPackageWithLibrary], but allows for more complex @@ -107,43 +123,33 @@ $libraryContent List show = const [], List hide = const []}) async { final subdir = reexportPrivate ? 'src' : 'subdir'; - await d.dir('lib', [ - d.dir(subdir, [ - d.file('lib.dart', ''' -library ${libraryName}_src; - -$reexportedContent -'''), - ]) - ]).createInMemory(resourceProvider, packagePath); - if (show.isNotEmpty && hide.isNotEmpty) { throw DartdocTestBaseFailure('Can not specify show and hide'); } - final showHideString = '${show.isNotEmpty ? 'show ${show.join(', ')}' : ''}' '${hide.isNotEmpty ? 'hide ${hide.join(', ')}' : ''}'; - await d.dir('lib', [ - d.file('lib.dart', ''' + + return (await _bootPackageFromFiles(() => [ + d.dir('lib', [ + d.dir(subdir, [ + d.file('lib.dart', ''' +library ${libraryName}_src; + +$reexportedContent +'''), + ]), + d.file('lib.dart', ''' library ${libraryName}_lib; export '$subdir/lib.dart' $showHideString; '''), - ]).createInMemory(resourceProvider, packagePath); - - await d.dir('lib', [ - d.file('importing_lib.dart', ''' + d.file('importing_lib.dart', ''' library $libraryName; - $libraryContent '''), - ]).createInMemory(resourceProvider, packagePath); - - var packageGraph = await bootBasicPackage( - packagePath, - packageMetaProvider, - packageConfigProvider, - ); - return packageGraph.libraries.named(libraryName); + ]) + ])) + .libraries + .named(libraryName); } } diff --git a/test/generator/file_structure_test.dart b/test/generator/file_structure_test.dart index 7656d3e73f..e17c88b3a3 100644 --- a/test/generator/file_structure_test.dart +++ b/test/generator/file_structure_test.dart @@ -6,6 +6,7 @@ import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; import '../dartdoc_test_base.dart'; +import '../src/test_descriptor_utils.dart' as d; import '../src/utils.dart'; void main() { @@ -22,9 +23,54 @@ class FileStructureTest extends DartdocTestBase { void test_fileNamesForModelElements() async { var library = await bootPackageWithLibrary(''' var globalVar = 123; -'''); +const globalConst = 123; + +class AClass { + const myConst = 75; + var myVariable = 76; + + void aMethod(); + + @override + operator+ (AClass b) => AClass(); +} + +mixin BMixin on AClass {} +''', + libraryPreamble: ''' +/// {@category MyCategory} +''', + extraFiles: () => [ + d.file('dartdoc_options.yaml', ''' +dartdoc: + categories: + "MyCategory": + markdown: MyCategory.md +'''), + d.file('MyCategory.md', ''' +Hello there, I am an *amazing* markdown file. +'''), + ]); var globalVar = library.properties.named('globalVar'); - var structure = globalVar.fileStructure; - expect(structure.fileName, equals('globalVar.html')); + var globalConst = library.constants.named('globalConst'); + var category = + library.package.categories.firstWhere((c) => c.name == 'MyCategory'); + var AClass = library.classes.named('AClass'); + var BMixin = library.mixins.named('BMixin'); + var myConst = AClass.constantFields.named('myConst'); + var myVariable = AClass.instanceFields.named('myVariable'); + var aMethod = AClass.instanceMethods.named('aMethod'); + var operatorPlus = AClass.instanceOperators.named('operator +'); + + expect(globalVar.fileStructure.fileName, equals('globalVar.html')); + expect(globalConst.fileStructure.fileName, + equals('globalConst-constant.html')); + expect(category.fileStructure.fileName, equals('MyCategory-topic.html')); + expect(AClass.fileStructure.fileName, equals('AClass-class.html')); + expect(BMixin.fileStructure.fileName, equals('BMixin-mixin.html')); + expect(myConst.fileStructure.fileName, equals('myConst-constant.html')); + expect(myVariable.fileStructure.fileName, equals('myVariable.html')); + expect(aMethod.fileStructure.fileName, equals('aMethod.html')); + expect(operatorPlus.fileStructure.fileName, equals('operator_plus.html')); } } From b0cdba92b6ff66df0e3584f1a4d7d4b6c9c068dc Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Fri, 12 May 2023 10:47:59 -0700 Subject: [PATCH 4/8] Clean up accidental relative autoimport --- lib/src/generator/file_structure.dart | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/lib/src/generator/file_structure.dart b/lib/src/generator/file_structure.dart index 47bfcc57b7..cd0280d3c8 100644 --- a/lib/src/generator/file_structure.dart +++ b/lib/src/generator/file_structure.dart @@ -4,18 +4,9 @@ import 'package:dartdoc/src/comment_references/parser.dart'; import 'package:dartdoc/src/failure.dart'; -import 'package:dartdoc/src/model/category.dart'; -import 'package:dartdoc/src/model/class.dart'; -import 'package:dartdoc/src/model/documentable.dart'; -import 'package:dartdoc/src/model/getter_setter_combo.dart'; -import 'package:dartdoc/src/model/library.dart'; -import 'package:dartdoc/src/model/library_container.dart'; -import 'package:dartdoc/src/model/model_element.dart'; -import 'package:dartdoc/src/model/operator.dart'; -import 'package:dartdoc/src/model/package.dart'; import 'package:meta/meta.dart'; -import '../model/mixin.dart'; +import '../model/model.dart'; const _validFormats = {'html', 'md'}; From 7b99e2f5f54de32210c798140ccb338e3860803e Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Fri, 12 May 2023 12:57:57 -0700 Subject: [PATCH 5/8] Add comment and fix grind race condition (again?) --- lib/src/model/enum.dart | 2 ++ tool/grind.dart | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/model/enum.dart b/lib/src/model/enum.dart index 0154b7c355..bb2c500201 100644 --- a/lib/src/model/enum.dart +++ b/lib/src/model/enum.dart @@ -113,6 +113,8 @@ class EnumField extends Field { assert(!(canonicalLibrary == null || canonicalEnclosingContainer == null)); assert(canonicalLibrary == library); assert(canonicalEnclosingContainer == enclosingElement); + // TODO(jcollins-g): EnumField should not depend on enclosingElement, but + // we sort of have to while we are half-converted to [FileStructure]. return '${package.baseHref}${enclosingElement.library.dirName}/${enclosingElement.fileStructure.fileName}'; } diff --git a/tool/grind.dart b/tool/grind.dart index 7b89cf3a82..f26f2308b6 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -72,11 +72,11 @@ Future get cleanFlutterRepo async { if (repoCompleter != null) { return repoCompleter.future; } - _cleanFlutterRepo = repoCompleter; // No await is allowed between check of _cleanFlutterRepo and its assignment, // to prevent reentering this function. repoCompleter = Completer(); + _cleanFlutterRepo = repoCompleter; // Figure out where the repository is supposed to be and lock updates for // it. From e9fbc7d79b7c2a860e279c40dce6e471ffef40bc Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Fri, 12 May 2023 14:41:23 -0700 Subject: [PATCH 6/8] review comments, format --- lib/src/generator/file_structure.dart | 54 +++++++++++---------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/lib/src/generator/file_structure.dart b/lib/src/generator/file_structure.dart index cd0280d3c8..9b88a25b09 100644 --- a/lib/src/generator/file_structure.dart +++ b/lib/src/generator/file_structure.dart @@ -38,55 +38,35 @@ abstract class FileStructure { factory FileStructure._fromLibraryContainer( LibraryContainer libraryContainer) { - String? kindAddition; - String? pathSafeName = libraryContainer.name; + final format = libraryContainer.config.format; switch (libraryContainer) { case Category(): - kindAddition = 'topic'; - break; + return FileStructureImpl(format, libraryContainer.name, 'topic'); case Package(): - pathSafeName = 'index'; - break; + return FileStructureImpl(format, 'index', null); default: throw UnimplementedError( 'Unrecognized LibraryContainer subtype: ${libraryContainer.runtimeType}'); } - - return FileStructureImpl( - libraryContainer.config.format, pathSafeName, kindAddition); } factory FileStructure._fromModelElement(ModelElement modelElement) { - String? kindAddition; - String? pathSafeName = modelElement.name; + final format = modelElement.config.format; switch (modelElement) { case Library(): - kindAddition = 'library'; - pathSafeName = modelElement.dirName; - break; + return FileStructureImpl(format, modelElement.dirName, 'library'); case Mixin(): - kindAddition = 'mixin'; - break; + return FileStructureImpl(format, modelElement.name, 'mixin'); case Class(): - kindAddition = 'class'; - break; + return FileStructureImpl(format, modelElement.name, 'class'); case Operator(): - var referenceName = modelElement.referenceName; - if (operatorNames.containsKey(referenceName)) { - pathSafeName = 'operator_${operatorNames[referenceName]}'; - } - break; + return FileStructureImpl(format, 'operator_${operatorNames[modelElement.referenceName]}', null); case GetterSetterCombo(): - if (modelElement.isConst) { - kindAddition = 'constant'; - } - break; + return FileStructureImpl(format, modelElement.name, modelElement.isConst ? 'constant' : null); default: - break; + return FileStructureImpl( + modelElement.config.format, modelElement.name, null); } - - return FileStructureImpl( - modelElement.config.format, pathSafeName, kindAddition); } /// True if an independent file should be created for this `ModelElement`. @@ -118,13 +98,23 @@ abstract class FileStructure { class FileStructureImpl implements FileStructure { @override final String fileType; + + /// 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; + + /// 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; FileStructureImpl(this.fileType, this.pathSafeName, this.kindAddition); @override - /// 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]. From 442192f6c374f914ef66d5ae22e361b99388c9e8 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Fri, 12 May 2023 14:42:50 -0700 Subject: [PATCH 7/8] dartfmt --- lib/src/generator/file_structure.dart | 9 ++++-- test/dartdoc_test_base.dart | 39 +++++++++++++------------ test/generator/file_structure_test.dart | 12 ++++---- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/lib/src/generator/file_structure.dart b/lib/src/generator/file_structure.dart index 9b88a25b09..b8e1776193 100644 --- a/lib/src/generator/file_structure.dart +++ b/lib/src/generator/file_structure.dart @@ -60,12 +60,14 @@ abstract class FileStructure { case Class(): return FileStructureImpl(format, modelElement.name, 'class'); case Operator(): - return FileStructureImpl(format, 'operator_${operatorNames[modelElement.referenceName]}', null); + return FileStructureImpl(format, + 'operator_${operatorNames[modelElement.referenceName]}', null); case GetterSetterCombo(): - return FileStructureImpl(format, modelElement.name, modelElement.isConst ? 'constant' : null); + return FileStructureImpl(format, modelElement.name, + modelElement.isConst ? 'constant' : null); default: return FileStructureImpl( - modelElement.config.format, modelElement.name, null); + modelElement.config.format, modelElement.name, null); } } @@ -115,6 +117,7 @@ class FileStructureImpl implements FileStructure { FileStructureImpl(this.fileType, this.pathSafeName, this.kindAddition); @override + /// 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]. diff --git a/test/dartdoc_test_base.dart b/test/dartdoc_test_base.dart index ef89bc9b6a..a660d051ee 100644 --- a/test/dartdoc_test_base.dart +++ b/test/dartdoc_test_base.dart @@ -11,8 +11,6 @@ import 'package:meta/meta.dart'; import 'src/test_descriptor_utils.dart' as d; import 'src/utils.dart'; -typedef FileGenerator = Iterable Function(); - /// Exception thrown for invalid use of [DartdocTestBase]'s api. class DartdocTestBaseFailure implements Exception { final String message; @@ -72,12 +70,13 @@ analyzer: packagePath, name, Uri.file('$packagePath/')); } - Future _bootPackageFromFiles(FileGenerator files) async { + Future _bootPackageFromFiles( + Iterable files) async { var packagePathBasename = resourceProvider.pathContext.basename(packagePath); var packagePathDirname = resourceProvider.pathContext.dirname(packagePath); await d - .dir(packagePathBasename, files()) + .dir(packagePathBasename, files) .createInMemory(resourceProvider, packagePathDirname); return await bootBasicPackage( packagePath, @@ -90,17 +89,19 @@ analyzer: /// [libraryPreamble]. Optionally, pass a [FileGenerator] to create /// extra files in the package such as `dartdoc_options.yaml`. Future bootPackageWithLibrary(String libraryContent, - {String libraryPreamble = '', FileGenerator? extraFiles}) async { - return (await _bootPackageFromFiles(() => [ - d.dir('lib', [ - d.file('lib.dart', ''' + {String libraryPreamble = '', + Iterable extraFiles = const []}) async { + return (await _bootPackageFromFiles([ + d.dir('lib', [ + d.file('lib.dart', ''' $libraryPreamble library $libraryName; $libraryContent '''), - ]), - ])) + ]), + ...extraFiles + ])) .libraries .named(libraryName); } @@ -129,26 +130,26 @@ $libraryContent final showHideString = '${show.isNotEmpty ? 'show ${show.join(', ')}' : ''}' '${hide.isNotEmpty ? 'hide ${hide.join(', ')}' : ''}'; - return (await _bootPackageFromFiles(() => [ - d.dir('lib', [ - d.dir(subdir, [ - d.file('lib.dart', ''' + return (await _bootPackageFromFiles([ + d.dir('lib', [ + d.dir(subdir, [ + d.file('lib.dart', ''' library ${libraryName}_src; $reexportedContent '''), - ]), - d.file('lib.dart', ''' + ]), + d.file('lib.dart', ''' library ${libraryName}_lib; export '$subdir/lib.dart' $showHideString; '''), - d.file('importing_lib.dart', ''' + d.file('importing_lib.dart', ''' library $libraryName; $libraryContent '''), - ]) - ])) + ]) + ])) .libraries .named(libraryName); } diff --git a/test/generator/file_structure_test.dart b/test/generator/file_structure_test.dart index e17c88b3a3..0005f68a4f 100644 --- a/test/generator/file_structure_test.dart +++ b/test/generator/file_structure_test.dart @@ -36,21 +36,19 @@ class AClass { } mixin BMixin on AClass {} -''', - libraryPreamble: ''' +''', libraryPreamble: ''' /// {@category MyCategory} -''', - extraFiles: () => [ - d.file('dartdoc_options.yaml', ''' +''', extraFiles: [ + d.file('dartdoc_options.yaml', ''' dartdoc: categories: "MyCategory": markdown: MyCategory.md '''), - d.file('MyCategory.md', ''' + d.file('MyCategory.md', ''' Hello there, I am an *amazing* markdown file. '''), - ]); + ]); var globalVar = library.properties.named('globalVar'); var globalConst = library.constants.named('globalConst'); var category = From f65342da438321743e9a45a316a97d09a871e688 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Fri, 12 May 2023 15:17:44 -0700 Subject: [PATCH 8/8] windows test failure? --- test/generator/file_structure_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/generator/file_structure_test.dart b/test/generator/file_structure_test.dart index 0005f68a4f..e79b833743 100644 --- a/test/generator/file_structure_test.dart +++ b/test/generator/file_structure_test.dart @@ -43,9 +43,9 @@ mixin BMixin on AClass {} dartdoc: categories: "MyCategory": - markdown: MyCategory.md + markdown: mycategory.md '''), - d.file('MyCategory.md', ''' + d.file('mycategory.md', ''' Hello there, I am an *amazing* markdown file. '''), ]);