diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml index 04bf2346827..3932f63dce2 100644 --- a/pkg/analyzer/pubspec.yaml +++ b/pkg/analyzer/pubspec.yaml @@ -33,6 +33,7 @@ dev_dependencies: analysis_server_client: any analyzer_testing: any analyzer_utilities: any + api_summary: any args: any async: any checks: any diff --git a/pkg/analyzer/tool/api/generate.dart b/pkg/analyzer/tool/api/generate.dart index 0a1794cf291..e79396f7526 100644 --- a/pkg/analyzer/tool/api/generate.dart +++ b/pkg/analyzer/tool/api/generate.dart @@ -9,9 +9,9 @@ import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer_testing/package_root.dart' as pkg_root; -import 'package:analyzer_utilities/src/api_summary/src/api_summary_customizer.dart'; import 'package:analyzer_utilities/tool/api.dart'; import 'package:analyzer_utilities/tools.dart'; +import 'package:api_summary/api_summary.dart'; Future main() async { await GeneratedContent.generateAll(pkg_root.packageRoot, allTargets); diff --git a/pkg/analyzer_utilities/lib/tool/api.dart b/pkg/analyzer_utilities/lib/tool/api.dart index f20afe9a596..92c62df9d38 100644 --- a/pkg/analyzer_utilities/lib/tool/api.dart +++ b/pkg/analyzer_utilities/lib/tool/api.dart @@ -5,7 +5,7 @@ /// Generates the file `api.txt`, which describes a package's public API. library; -import 'package:analyzer_utilities/src/api_summary/summarize_package.dart'; +import 'package:api_summary/api_summary.dart'; import 'package:analyzer_utilities/tools.dart'; import 'package:path/path.dart'; diff --git a/pkg/analyzer_utilities/pubspec.yaml b/pkg/analyzer_utilities/pubspec.yaml index 6a76acff6d8..9b38e11eef8 100644 --- a/pkg/analyzer_utilities/pubspec.yaml +++ b/pkg/analyzer_utilities/pubspec.yaml @@ -11,6 +11,7 @@ resolution: workspace dependencies: analyzer: any analyzer_testing: any + api_summary: any collection: any package_config: any path: any @@ -23,4 +24,3 @@ dependencies: dev_dependencies: analyzer_plugin: any lints: any - test_reflective_loader: any diff --git a/pkg/api_summary/CHANGELOG.md b/pkg/api_summary/CHANGELOG.md new file mode 100644 index 00000000000..d4f1a2add78 --- /dev/null +++ b/pkg/api_summary/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.1.0-wip + +- First release. diff --git a/pkg/api_summary/LICENSE b/pkg/api_summary/LICENSE new file mode 100644 index 00000000000..9035a416a31 --- /dev/null +++ b/pkg/api_summary/LICENSE @@ -0,0 +1,27 @@ +Copyright 2026, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pkg/api_summary/OWNERS b/pkg/api_summary/OWNERS new file mode 100644 index 00000000000..a6bf39e3fd5 --- /dev/null +++ b/pkg/api_summary/OWNERS @@ -0,0 +1,3 @@ +file:/tools/OWNERS_DEVELOPER_EXPERIENCE +file:/tools/OWNERS_MODEL +kevmoo@google.com diff --git a/pkg/api_summary/README.md b/pkg/api_summary/README.md new file mode 100644 index 00000000000..06195ae2c79 --- /dev/null +++ b/pkg/api_summary/README.md @@ -0,0 +1 @@ +A tool to create a human-readable text summary of the public API of a Dart package. This is useful for auditing API changes with a `diff` tool. diff --git a/pkg/api_summary/analysis_options.yaml b/pkg/api_summary/analysis_options.yaml new file mode 100644 index 00000000000..aecda684d9b --- /dev/null +++ b/pkg/api_summary/analysis_options.yaml @@ -0,0 +1,5 @@ +include: package:dart_flutter_team_lints/analysis_options.yaml + +linter: + rules: + - unnecessary_ignore diff --git a/pkg/analyzer_utilities/lib/src/api_summary/summarize_package.dart b/pkg/api_summary/lib/api_summary.dart similarity index 82% rename from pkg/analyzer_utilities/lib/src/api_summary/summarize_package.dart rename to pkg/api_summary/lib/api_summary.dart index b2d4bd0b090..1963c6ff876 100644 --- a/pkg/analyzer_utilities/lib/src/api_summary/summarize_package.dart +++ b/pkg/api_summary/lib/api_summary.dart @@ -4,12 +4,11 @@ import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; import 'package:analyzer/file_system/physical_file_system.dart'; -import 'package:analyzer_utilities/src/api_summary/src/api_description.dart'; -import 'package:analyzer_utilities/src/api_summary/src/api_summary_customizer.dart'; -import 'package:analyzer_utilities/src/api_summary/src/node.dart'; +import 'src/api_description.dart'; +import 'src/api_summary_customizer.dart'; +import 'src/node.dart'; -export 'package:analyzer_utilities/src/api_summary/src/api_summary_customizer.dart' - show ApiSummaryCustomizer; +export 'src/api_summary_customizer.dart' show ApiSummaryCustomizer; /// Creates a human-readable text summary of the public API of a package, in a /// format suitable for auditing with a `diff` tool. diff --git a/pkg/analyzer_utilities/lib/src/api_summary/src/api_description.dart b/pkg/api_summary/lib/src/api_description.dart similarity index 96% rename from pkg/analyzer_utilities/lib/src/api_summary/src/api_description.dart rename to pkg/api_summary/lib/src/api_description.dart index 827f0d6cd3a..e6a69c4aade 100644 --- a/pkg/analyzer_utilities/lib/src/api_summary/src/api_description.dart +++ b/pkg/api_summary/lib/src/api_description.dart @@ -9,14 +9,15 @@ import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/nullability_suffix.dart'; import 'package:analyzer/dart/element/type.dart'; -import 'package:analyzer_utilities/src/api_summary/src/api_summary_customizer.dart'; -import 'package:analyzer_utilities/src/api_summary/src/extensions.dart'; -import 'package:analyzer_utilities/src/api_summary/src/member_sorting.dart'; -import 'package:analyzer_utilities/src/api_summary/src/node.dart'; -import 'package:analyzer_utilities/src/api_summary/src/unique_namer.dart'; -import 'package:analyzer_utilities/src/api_summary/src/uri_sorting.dart'; import 'package:collection/collection.dart'; +import 'api_summary_customizer.dart'; +import 'extensions.dart'; +import 'member_sorting.dart'; +import 'node.dart'; +import 'unique_namer.dart'; +import 'uri_sorting.dart'; + /// Data structure keeping track of a package's API while walking it to produce /// `api.txt`. class ApiDescription { @@ -244,7 +245,7 @@ class ApiDescription { var parentheticals = >[]; switch (element) { case TypeAliasElement(:var aliasedType, :var typeParameters): - List description = ['type alias']; + var description = ['type alias']; if (typeParameters.isNotEmpty) { description.addAll( typeParameters @@ -261,7 +262,7 @@ class ApiDescription { :var supertype, :var interfaces, ): - List instanceDescription = [ + var instanceDescription = [ switch (element) { ClassElement() => 'class', EnumElement() => 'enum', @@ -388,7 +389,7 @@ class ApiDescription { case TopLevelFunctionElement(:var type): parentheticals.add(['function: ', ..._describeType(type)]); case ExecutableElement(:var isStatic): - String maybeStatic = isStatic ? 'static ' : ''; + var maybeStatic = isStatic ? 'static ' : ''; switch (element) { case GetterElement(:var type): parentheticals.add([ @@ -433,7 +434,7 @@ class ApiDescription { } } - /// Appends information to [node] describing [element]. + /// Appends information to [node] describing [library]. void _dumpLibrary(LibraryElement library, Node node) { var uri = library.uri; node.text.addAll([uri, ':']); diff --git a/pkg/analyzer_utilities/lib/src/api_summary/src/api_summary_customizer.dart b/pkg/api_summary/lib/src/api_summary_customizer.dart similarity index 95% rename from pkg/analyzer_utilities/lib/src/api_summary/src/api_summary_customizer.dart rename to pkg/api_summary/lib/src/api_summary_customizer.dart index 9d0c3e07448..34c68451487 100644 --- a/pkg/analyzer_utilities/lib/src/api_summary/src/api_summary_customizer.dart +++ b/pkg/api_summary/lib/src/api_summary_customizer.dart @@ -46,7 +46,8 @@ base class ApiSummaryCustomizer { /// Called after [initialScanComplete] to determine if details about an /// element should be shown in the API summary. /// - /// The default behavior is to show details about elements in [topLevelPublicElements]. + /// The default behavior is to show details about elements in + /// [topLevelPublicElements]. bool shouldShowDetails(Element element) => topLevelPublicElements.contains(element); } diff --git a/pkg/analyzer_utilities/lib/src/api_summary/src/extensions.dart b/pkg/api_summary/lib/src/extensions.dart similarity index 100% rename from pkg/analyzer_utilities/lib/src/api_summary/src/extensions.dart rename to pkg/api_summary/lib/src/extensions.dart diff --git a/pkg/analyzer_utilities/lib/src/api_summary/src/member_sorting.dart b/pkg/api_summary/lib/src/member_sorting.dart similarity index 100% rename from pkg/analyzer_utilities/lib/src/api_summary/src/member_sorting.dart rename to pkg/api_summary/lib/src/member_sorting.dart diff --git a/pkg/analyzer_utilities/lib/src/api_summary/src/node.dart b/pkg/api_summary/lib/src/node.dart similarity index 97% rename from pkg/analyzer_utilities/lib/src/api_summary/src/node.dart rename to pkg/api_summary/lib/src/node.dart index bd05469f5da..02f4bf46e68 100644 --- a/pkg/analyzer_utilities/lib/src/api_summary/src/node.dart +++ b/pkg/api_summary/lib/src/node.dart @@ -2,6 +2,9 @@ // 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. +/// @docImport 'unique_namer.dart'; +library; + import 'package:collection/collection.dart'; /// Outputs the contents of [nodes] to [sink], prepending [prefix] to every diff --git a/pkg/analyzer_utilities/lib/src/api_summary/src/unique_namer.dart b/pkg/api_summary/lib/src/unique_namer.dart similarity index 91% rename from pkg/analyzer_utilities/lib/src/api_summary/src/unique_namer.dart rename to pkg/api_summary/lib/src/unique_namer.dart index 8f243e022f2..d9bbb1bd020 100644 --- a/pkg/analyzer_utilities/lib/src/api_summary/src/unique_namer.dart +++ b/pkg/api_summary/lib/src/unique_namer.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer_utilities/src/api_summary/src/extensions.dart'; +import 'extensions.dart'; /// Object that will have a unique string representation within the context of a /// given [UniqueNamer] instance. @@ -21,9 +21,9 @@ class UniqueName { /// [UniqueName] from other ones with the same [_nameHint]. int? _disambiguator; - UniqueName(UniqueNamer uniqueNamer, this._nameHint) { + UniqueName(UniqueNamer uniqueNamer, this._nameHint) // The uniqueness guarantee depends on `_nameHint` not containing an `@`. - assert(!_nameHint.contains('@')); + : assert(!_nameHint.contains('@')) { var conflicts = uniqueNamer._conflicts[_nameHint] ??= []; if (conflicts.length == 1) { conflicts[0]._disambiguator = 1; diff --git a/pkg/analyzer_utilities/lib/src/api_summary/src/uri_sorting.dart b/pkg/api_summary/lib/src/uri_sorting.dart similarity index 93% rename from pkg/analyzer_utilities/lib/src/api_summary/src/uri_sorting.dart rename to pkg/api_summary/lib/src/uri_sorting.dart index e86587b726e..0ba179492a9 100644 --- a/pkg/analyzer_utilities/lib/src/api_summary/src/uri_sorting.dart +++ b/pkg/api_summary/lib/src/uri_sorting.dart @@ -2,7 +2,7 @@ // 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:analyzer_utilities/src/api_summary/src/extensions.dart'; +import 'extensions.dart'; /// URI categorization used by [UriSortKey]. enum UriCategory { inPackage, notInPackage } diff --git a/pkg/api_summary/pubspec.yaml b/pkg/api_summary/pubspec.yaml new file mode 100644 index 00000000000..36303ccac3a --- /dev/null +++ b/pkg/api_summary/pubspec.yaml @@ -0,0 +1,21 @@ +name: api_summary +version: 0.1.0-wip +description: Creates an API summary for a package. +publish_to: none + +environment: + sdk: '^3.12.0-0' + +resolution: workspace + +# Use 'any' constraints here; we get our versions from the DEPS file. +dependencies: + analyzer: any + collection: any + +# Use 'any' constraints here; we get our versions from the DEPS file. +dev_dependencies: + analyzer_testing: any + dart_flutter_team_lints: any + test: any + test_reflective_loader: any diff --git a/pkg/analyzer_utilities/test/api_summary/src/api_description_test.dart b/pkg/api_summary/test/api_description_test.dart similarity index 98% rename from pkg/analyzer_utilities/test/api_summary/src/api_description_test.dart rename to pkg/api_summary/test/api_description_test.dart index 944320be577..de91d092a22 100644 --- a/pkg/analyzer_utilities/test/api_summary/src/api_description_test.dart +++ b/pkg/api_summary/test/api_description_test.dart @@ -8,13 +8,13 @@ import 'dart:core'; import 'package:analyzer/dart/analysis/analysis_context.dart'; import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer_utilities/src/api_summary/src/api_description.dart'; -import 'package:analyzer_utilities/src/api_summary/src/api_summary_customizer.dart'; -import 'package:analyzer_utilities/src/api_summary/src/node.dart'; +import 'package:api_summary/src/api_description.dart'; +import 'package:api_summary/src/api_summary_customizer.dart'; +import 'package:api_summary/src/node.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; -import '../utilities.dart'; +import 'test_utils.dart'; void main() { defineReflectiveSuite(() { @@ -141,8 +141,8 @@ dart:core: } Future test_field_experimental() async { - // Marking a field as experimental causes its corresponding getter and setter - // to be marked as experimental in the summary. + // Marking a field as experimental causes its corresponding getter and + // setter to be marked as experimental in the summary. var summary = await _build({ '$testPackageLibPath/file.dart': ''' import 'package:meta/meta.dart'; diff --git a/pkg/analyzer_utilities/test/api_summary/src/extensions_test.dart b/pkg/api_summary/test/extensions_test.dart similarity index 97% rename from pkg/analyzer_utilities/test/api_summary/src/extensions_test.dart rename to pkg/api_summary/test/extensions_test.dart index f08e04a0c67..eb76ad90326 100644 --- a/pkg/analyzer_utilities/test/api_summary/src/extensions_test.dart +++ b/pkg/api_summary/test/extensions_test.dart @@ -4,11 +4,11 @@ // ignore_for_file: non_constant_identifier_names -import 'package:analyzer_utilities/src/api_summary/src/extensions.dart'; +import 'package:api_summary/src/extensions.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; -import '../utilities.dart'; +import 'test_utils.dart'; void main() { defineReflectiveSuite(() { diff --git a/pkg/analyzer_utilities/test/api_summary/src/member_sorting_test.dart b/pkg/api_summary/test/member_sorting_test.dart similarity index 94% rename from pkg/analyzer_utilities/test/api_summary/src/member_sorting_test.dart rename to pkg/api_summary/test/member_sorting_test.dart index c723c5ab258..fe1d8f793b3 100644 --- a/pkg/analyzer_utilities/test/api_summary/src/member_sorting_test.dart +++ b/pkg/api_summary/test/member_sorting_test.dart @@ -5,13 +5,13 @@ // ignore_for_file: non_constant_identifier_names import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer_utilities/src/api_summary/src/extensions.dart'; -import 'package:analyzer_utilities/src/api_summary/src/member_sorting.dart'; +import 'package:api_summary/src/extensions.dart'; +import 'package:api_summary/src/member_sorting.dart'; import 'package:collection/collection.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; -import '../utilities.dart'; +import 'test_utils.dart'; void main() { defineReflectiveSuite(() { @@ -183,12 +183,12 @@ typedef Z3 = int; required List expectedOrder, }) { expect( - elements.sortedBy((e) => MemberSortKey(e)).map((e) => e.apiName).toList(), + elements.sortedBy(MemberSortKey.new).map((e) => e.apiName).toList(), expectedOrder, ); expect( elements.reversed - .sortedBy((e) => MemberSortKey(e)) + .sortedBy(MemberSortKey.new) .map((e) => e.apiName) .toList(), expectedOrder, diff --git a/pkg/analyzer_utilities/test/api_summary/src/node_test.dart b/pkg/api_summary/test/node_test.dart similarity index 96% rename from pkg/analyzer_utilities/test/api_summary/src/node_test.dart rename to pkg/api_summary/test/node_test.dart index 8ce6eee927e..90879d0cffd 100644 --- a/pkg/analyzer_utilities/test/api_summary/src/node_test.dart +++ b/pkg/api_summary/test/node_test.dart @@ -4,7 +4,7 @@ // ignore_for_file: non_constant_identifier_names -import 'package:analyzer_utilities/src/api_summary/src/node.dart'; +import 'package:api_summary/src/node.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; diff --git a/pkg/analyzer_utilities/test/api_summary/utilities.dart b/pkg/api_summary/test/test_utils.dart similarity index 100% rename from pkg/analyzer_utilities/test/api_summary/utilities.dart rename to pkg/api_summary/test/test_utils.dart diff --git a/pkg/analyzer_utilities/test/api_summary/src/unique_namer_test.dart b/pkg/api_summary/test/unique_namer_test.dart similarity index 96% rename from pkg/analyzer_utilities/test/api_summary/src/unique_namer_test.dart rename to pkg/api_summary/test/unique_namer_test.dart index 52bc1665b4b..80df390143d 100644 --- a/pkg/analyzer_utilities/test/api_summary/src/unique_namer_test.dart +++ b/pkg/api_summary/test/unique_namer_test.dart @@ -4,11 +4,11 @@ // ignore_for_file: non_constant_identifier_names -import 'package:analyzer_utilities/src/api_summary/src/unique_namer.dart'; +import 'package:api_summary/src/unique_namer.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; -import '../utilities.dart'; +import 'test_utils.dart'; void main() { defineReflectiveSuite(() { diff --git a/pkg/analyzer_utilities/test/api_summary/src/uri_sorting_test.dart b/pkg/api_summary/test/uri_sorting_test.dart similarity index 94% rename from pkg/analyzer_utilities/test/api_summary/src/uri_sorting_test.dart rename to pkg/api_summary/test/uri_sorting_test.dart index b3ef7c12d54..3d7a541a93b 100644 --- a/pkg/analyzer_utilities/test/api_summary/src/uri_sorting_test.dart +++ b/pkg/api_summary/test/uri_sorting_test.dart @@ -4,7 +4,7 @@ // ignore_for_file: non_constant_identifier_names -import 'package:analyzer_utilities/src/api_summary/src/uri_sorting.dart'; +import 'package:api_summary/src/uri_sorting.dart'; import 'package:collection/collection.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 4f4725d8f63..852d4cad6e8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,6 +19,7 @@ workspace: - pkg/analysis_server_client - pkg/analysis_server_plugin - pkg/analyzer + - pkg/api_summary - pkg/analyzer_cli - pkg/analyzer_plugin - pkg/analyzer_testing diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json index 58a0cbf2db2..ff28fa0ac83 100644 --- a/tools/bots/test_matrix.json +++ b/tools/bots/test_matrix.json @@ -2932,7 +2932,7 @@ "name": "unit tests", "arguments": [ "-nanalyzer-unittest-asserts-${mode}-${system}", - "pkg/(analyzer|analysis_server|analysis_server_plugin|analyzer_cli|analyzer_plugin)" + "pkg/(analyzer|analysis_server|analysis_server_plugin|analyzer_cli|analyzer_plugin|api_summary)" ], "shards": 9, "fileset": "analyzer_unit_tests" @@ -3015,6 +3015,13 @@ "pkg/analyzer_plugin" ] }, + { + "name": "api_summary unit tests", + "arguments": [ + "-nanalyzer-unittest-asserts-${mode}-${system}", + "pkg/api_summary" + ] + }, { "name": "benchmark analysis server", "script": "out/ReleaseX64/dart-sdk/bin/dart",