Version 2.18.0-229.0.dev
Merge commit '057d0baaf9a7b060c3df8fcf07b4f70603d65b42' into 'dev'
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 8571ef7..b63c3f2 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -1,7 +1,8 @@
-<!DOCTYPE html><html><head>
+<!DOCTYPE html><html>
+<head>
<meta charset="UTF-8">
<title>Analysis Server API Specification</title>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@300;400;700&family=Roboto:ital,wght@0,300;0,400;0,700;1,400&display=swap" type="text/css"><style>body {
+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@300;400;700&family=Roboto:ital,wght@0,300;0,400;0,700;1,400&display=swap" type="text/css"><style>body {
font-family: 'Roboto', sans-serif;
max-width: 800px;
margin: 0 auto;
@@ -6361,6 +6362,5 @@
</p>
<h2 class="domain"><a name="index">Index</a></h2>
<h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li><li><a href="#request_server.cancelRequest">cancelRequest</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.log">log</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.closingLabels">closingLabels</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li><li><a href="#request_completion.getSuggestions2">getSuggestions2</a></li><li><a href="#request_completion.setSubscriptions">setSubscriptions</a></li><li><a href="#request_completion.registerLibraryPaths">registerLibraryPaths</a></li><li><a href="#request_completion.getSuggestionDetails">getSuggestionDetails</a></li><li><a href="#request_completion.getSuggestionDetails2">getSuggestionDetails2</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li><li><a href="#notification_completion.availableSuggestions">availableSuggestions</a></li><li><a href="#notification_completion.existingImports">existingImports</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getPostfixCompletion">getPostfixCompletion</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.getSuggestions">getSuggestions</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li><li><a href="#request_diagnostic.getServerPort">getServerPort</a></li></ul></div><h4>flutter (<a href="#domain_flutter">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_flutter.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_flutter.outline">outline</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_AvailableSuggestion">AvailableSuggestion</a></li><li><a href="#type_AvailableSuggestionRelevanceTag">AvailableSuggestionRelevanceTag</a></li><li><a href="#type_AvailableSuggestionSet">AvailableSuggestionSet</a></li><li><a href="#type_BulkFix">BulkFix</a></li><li><a href="#type_BulkFixDetail">BulkFixDetail</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_ClosingLabel">ClosingLabel</a></li><li><a href="#type_CompletionCaseMatchingMode">CompletionCaseMatchingMode</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionMode">CompletionMode</a></li><li><a href="#type_CompletionService">CompletionService</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextData">ContextData</a></li><li><a href="#type_DiagnosticMessage">DiagnosticMessage</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementDeclaration">ElementDeclaration</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_ExistingImport">ExistingImport</a></li><li><a href="#type_ExistingImports">ExistingImports</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FlutterOutline">FlutterOutline</a></li><li><a href="#type_FlutterOutlineAttribute">FlutterOutlineAttribute</a></li><li><a href="#type_FlutterOutlineKind">FlutterOutlineKind</a></li><li><a href="#type_FlutterService">FlutterService</a></li><li><a href="#type_FlutterWidgetProperty">FlutterWidgetProperty</a></li><li><a href="#type_FlutterWidgetPropertyEditor">FlutterWidgetPropertyEditor</a></li><li><a href="#type_FlutterWidgetPropertyEditorKind">FlutterWidgetPropertyEditorKind</a></li><li><a href="#type_FlutterWidgetPropertyValue">FlutterWidgetPropertyValue</a></li><li><a href="#type_FlutterWidgetPropertyValueEnumItem">FlutterWidgetPropertyValueEnumItem</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_ImportedElementSet">ImportedElementSet</a></li><li><a href="#type_ImportedElements">ImportedElements</a></li><li><a href="#type_IncludedSuggestionRelevanceTag">IncludedSuggestionRelevanceTag</a></li><li><a href="#type_IncludedSuggestionSet">IncludedSuggestionSet</a></li><li><a href="#type_KytheEntry">KytheEntry</a></li><li><a href="#type_KytheVName">KytheVName</a></li><li><a href="#type_LibraryPathSet">LibraryPathSet</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PostfixTemplateDescriptor">PostfixTemplateDescriptor</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_RuntimeCompletionExpression">RuntimeCompletionExpression</a></li><li><a href="#type_RuntimeCompletionExpressionType">RuntimeCompletionExpressionType</a></li><li><a href="#type_RuntimeCompletionExpressionTypeKind">RuntimeCompletionExpressionTypeKind</a></li><li><a href="#type_RuntimeCompletionVariable">RuntimeCompletionVariable</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_EXTRACT_WIDGET">EXTRACT_WIDGET</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
-
-
-</body></html>
\ No newline at end of file
+</body>
+</html>
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 7df20d4..555ede3 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -29,7 +29,6 @@
dev_dependencies:
analyzer_utilities: any
cli_util: any
- html: any
lints: any
logging: any
matcher: any
diff --git a/pkg/analysis_server/tool/spec/api.dart b/pkg/analysis_server/tool/spec/api.dart
index 45fdf69..b0f4555 100644
--- a/pkg/analysis_server/tool/spec/api.dart
+++ b/pkg/analysis_server/tool/spec/api.dart
@@ -6,7 +6,7 @@
/// for visiting those data structures.
import 'dart:collection';
-import 'package:html/dom.dart' as dom;
+import 'package:analyzer_utilities/html_dom.dart' as dom;
/// Toplevel container for the API.
class Api extends ApiNode {
@@ -303,8 +303,7 @@
/// Base class for all possible types.
abstract class TypeDecl extends ApiNode {
- TypeDecl(super.html,
- {super.experimental, super.deprecated});
+ TypeDecl(super.html, {super.experimental, super.deprecated});
T accept<T>(ApiVisitor<T> visitor);
}
@@ -413,6 +412,9 @@
bool experimental = false,
bool deprecated = false})
: super(html, experimental: experimental, deprecated: deprecated);
+
+ @override
+ String toString() => name;
}
/// A reference to a type which is either defined elsewhere in the API or which
diff --git a/pkg/analysis_server/tool/spec/codegen_dart_notification_handler.dart b/pkg/analysis_server/tool/spec/codegen_dart_notification_handler.dart
index d8bf61f..1122cee 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart_notification_handler.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart_notification_handler.dart
@@ -2,8 +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.
+import 'package:analyzer_utilities/html_dom.dart';
+import 'package:analyzer_utilities/html_generator.dart';
import 'package:analyzer_utilities/tools.dart';
-import 'package:html/dom.dart';
import 'api.dart';
import 'codegen_dart.dart';
@@ -24,7 +25,7 @@
List<String> _generateDartDoc(Element html) => html.children
.where((Element elem) => elem.localName == 'p')
- .map<String>((Element elem) => elem.text.trim())
+ .map<String>((Element elem) => innerText(elem).trim())
.toList();
String _generateNotificationMethodName(String domainName, String event) =>
diff --git a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
index 9566809..7ee51f7 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
@@ -4,8 +4,8 @@
import 'dart:convert';
+import 'package:analyzer_utilities/html_dom.dart' as dom;
import 'package:analyzer_utilities/tools.dart';
-import 'package:html/dom.dart' as dom;
import 'package:path/path.dart' as path;
import 'api.dart';
diff --git a/pkg/analysis_server/tool/spec/codegen_java.dart b/pkg/analysis_server/tool/spec/codegen_java.dart
index 1143012..5bfd161 100644
--- a/pkg/analysis_server/tool/spec/codegen_java.dart
+++ b/pkg/analysis_server/tool/spec/codegen_java.dart
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
/// Tools for Java code generation.
+import 'package:analyzer_utilities/html_dom.dart' as dom;
import 'package:analyzer_utilities/tools.dart';
-import 'package:html/dom.dart' as dom;
import 'api.dart';
import 'from_html.dart';
@@ -51,8 +51,7 @@
/// Visitor used to produce doc comments.
final ToHtmlVisitor toHtmlVisitor;
- CodegenJavaVisitor(super.api)
- : toHtmlVisitor = ToHtmlVisitor(api);
+ CodegenJavaVisitor(super.api) : toHtmlVisitor = ToHtmlVisitor(api);
/// Create a constructor, using [callback] to create its contents.
void constructor(String name, void Function() callback) {
diff --git a/pkg/analysis_server/tool/spec/codegen_java_types.dart b/pkg/analysis_server/tool/spec/codegen_java_types.dart
index 6431566..d8eea5c 100644
--- a/pkg/analysis_server/tool/spec/codegen_java_types.dart
+++ b/pkg/analysis_server/tool/spec/codegen_java_types.dart
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
/// Code generation for the file "AnalysisServer.java".
+import 'package:analyzer_utilities/html_dom.dart' as dom;
import 'package:analyzer_utilities/tools.dart';
-import 'package:html/dom.dart' as dom;
import 'api.dart';
import 'codegen_java.dart';
diff --git a/pkg/analysis_server/tool/spec/from_html.dart b/pkg/analysis_server/tool/spec/from_html.dart
index d3a1ce7..0b6d2ef 100644
--- a/pkg/analysis_server/tool/spec/from_html.dart
+++ b/pkg/analysis_server/tool/spec/from_html.dart
@@ -5,9 +5,8 @@
/// Code for reading an HTML API description.
import 'dart:io';
-import 'package:analyzer_utilities/html.dart';
-import 'package:html/dom.dart' as dom;
-import 'package:html/parser.dart' as parser;
+import 'package:analyzer_utilities/html_dom.dart' as dom;
+import 'package:analyzer_utilities/html_generator.dart';
import 'package:path/path.dart';
import 'api.dart';
@@ -21,8 +20,6 @@
typedef ElementProcessor = void Function(dom.Element element);
-typedef TextProcessor = void Function(dom.Text text);
-
class ApiReader {
static const List<String> specialElements = [
'domain',
@@ -109,10 +106,6 @@
{List<String> optionalAttributes = const []}) {
var attributesFound = <String>{};
element.attributes.forEach((name, value) {
- if (name is! String) {
- throw Exception(
- '$context: Only string attribute names expected: $name');
- }
if (!requiredAttributes.contains(name) &&
!optionalAttributes.contains(name)) {
throw Exception(
@@ -319,8 +312,9 @@
/// Read the API description from file with the given [filePath].
Api readApi() {
- var htmlContents = File(filePath).readAsStringSync();
- var document = parser.parse(htmlContents);
+ var file = File(filePath);
+ var htmlContents = file.readAsStringSync();
+ var document = dom.parse(htmlContents, file.uri);
var htmlElement = document.children
.singleWhere((element) => element.localName!.toLowerCase() == 'html');
return apiFromHtml(htmlElement);
diff --git a/pkg/analysis_server/tool/spec/to_html.dart b/pkg/analysis_server/tool/spec/to_html.dart
index 7d4a72eb..d5f865d 100644
--- a/pkg/analysis_server/tool/spec/to_html.dart
+++ b/pkg/analysis_server/tool/spec/to_html.dart
@@ -7,9 +7,9 @@
/// in generated code.
import 'dart:convert';
-import 'package:analyzer_utilities/html.dart';
+import 'package:analyzer_utilities/html_dom.dart' as dom;
+import 'package:analyzer_utilities/html_generator.dart';
import 'package:analyzer_utilities/tools.dart';
-import 'package:html/dom.dart' as dom;
import 'api.dart';
import 'from_html.dart';
@@ -127,7 +127,6 @@
GeneratedFile('doc/api.html', (String pkgPath) async {
var visitor = ToHtmlVisitor(readApi(pkgPath));
var document = dom.Document();
- document.append(dom.DocumentType('html', null, null));
for (var node in visitor.collectHtml(visitor.visitApi)) {
document.append(node);
}
@@ -169,7 +168,7 @@
void dl(void Function() callback) => element('dl', {}, callback);
void dt(String cls, void Function() callback) =>
element('dt', {'class': cls}, callback);
- void element(String name, Map<Object, String> attributes,
+ void element(String name, Map<String, String> attributes,
[void Function() callback]);
void gray(void Function() callback) =>
element('span', {'style': 'color:#999999'}, callback);
@@ -188,7 +187,7 @@
void i(void Function() callback) => element('i', {}, callback);
void li(void Function() callback) => element('li', {}, callback);
void link(String id, void Function() callback,
- [Map<Object, String>? attributes]) {
+ [Map<String, String>? attributes]) {
attributes ??= {};
attributes['href'] = '#$id';
element('a', attributes, callback);
@@ -212,8 +211,7 @@
/// Mappings from HTML elements to API nodes.
ApiMappings apiMappings;
- ToHtmlVisitor(super.api)
- : apiMappings = ApiMappings(api) {
+ ToHtmlVisitor(super.api) : apiMappings = ApiMappings(api) {
apiMappings.visitApi();
}
@@ -470,7 +468,7 @@
}
}
} else if (node is dom.Text) {
- var text = node.text;
+ var text = node.textRemoveTags;
write(text);
}
}
diff --git a/pkg/analyzer/lib/src/manifest/manifest_validator.dart b/pkg/analyzer/lib/src/manifest/manifest_validator.dart
index ff88bff..1ceb595 100644
--- a/pkg/analyzer/lib/src/manifest/manifest_validator.dart
+++ b/pkg/analyzer/lib/src/manifest/manifest_validator.dart
@@ -34,13 +34,13 @@
/// (https://www.w3.org/TR/xml/#sec-references).
class ManifestParser {
/// Elements which are relevant to manifest validation.
- static const List<String> _relevantElements = [
+ static const Set<String> _manifestValidationElements = {
ACTIVITY_TAG,
APPLICATION_TAG,
MANIFEST_TAG,
USES_FEATURE_TAG,
USES_PERMISSION_TAG
- ];
+ };
/// The text of the Android Manifest file.
final String content;
@@ -49,12 +49,23 @@
/// purposes.
final SourceFile sourceFile;
+ /// The set of element types to return.
+ final Set<String>? restrictElements;
+
/// The current offset in the source file.
int _pos;
ManifestParser(this.content, Uri uri)
: sourceFile = SourceFile.fromString(content, url: uri),
- _pos = 0;
+ _pos = 0,
+ restrictElements = _manifestValidationElements;
+
+ ManifestParser.general(
+ this.content, {
+ required Uri uri,
+ }) : sourceFile = SourceFile.fromString(content, url: uri),
+ _pos = 0,
+ restrictElements = null;
/// Whether the current character is a tag-closing character (">").
bool get _isClosing =>
@@ -115,7 +126,8 @@
/// Returns whether [name] represents an element that is relevant to manifest
/// validation.
- bool _isRelevantElement(String name) => _relevantElements.contains(name);
+ bool _isRelevantElement(String name) =>
+ restrictElements?.contains(name) ?? true;
/// Parses any whitespace, returning `null` when non-whitespace is parsed.
ParseResult? _parseAnyWhitespace() {
@@ -134,7 +146,7 @@
/// Parses an attribute.
ParseAttributeResult _parseAttribute(bool isRelevant) {
- var attributes = <String, _XmlAttribute>{};
+ var attributes = <String, XmlAttribute>{};
bool isEmptyElement;
while (true) {
@@ -221,7 +233,7 @@
var attributeValue = content.substring(attributeValuePos, _pos);
var sourceSpan = sourceFile.span(attributeNamePos, _pos);
attributes[attributeName] =
- _XmlAttribute(attributeName, attributeValue, sourceSpan);
+ XmlAttribute(attributeName, attributeValue, sourceSpan);
}
_pos++;
}
@@ -323,7 +335,7 @@
if (_isClosing) {
// End tags cannot have attributes.
return ParseTagResult(
- ParseResult.endTag, _XmlElement(name, {}, [], null));
+ ParseResult.endTag, XmlElement(name, {}, [], null));
} else {
return ParseTagResult.error;
}
@@ -331,7 +343,7 @@
var isRelevant = _isRelevantElement(name);
- Map<String, _XmlAttribute> attributes;
+ Map<String, XmlAttribute> attributes;
bool isEmptyElement;
if (tagClosingState == _TagClosingState.notClosed) {
// Have not parsed the tag close yet; parse attributes.
@@ -352,7 +364,7 @@
isEmptyElement = true;
}
- var children = <_XmlElement>[];
+ var children = <XmlElement>[];
if (!isEmptyElement) {
ParseTagResult child;
_pos++;
@@ -372,9 +384,9 @@
// Finished parsing start tag.
if (isRelevant) {
- var sourceSpan = sourceFile.span(startPos, _pos);
+ var sourceSpan = sourceFile.span(startPos, _pos + 1);
return ParseTagResult(ParseResult.relevantElement,
- _XmlElement(name, attributes, children, sourceSpan));
+ XmlElement(name, attributes, children, sourceSpan));
} else {
// Discard all parsed children. This requires the notion that all relevant
// tags are direct children of other relevant tags.
@@ -439,17 +451,17 @@
}
}
- bool _hasFeatureCamera(Iterable<_XmlElement> features) => features
+ bool _hasFeatureCamera(Iterable<XmlElement> features) => features
.any((f) => f.attributes[ANDROID_NAME]?.value == HARDWARE_FEATURE_CAMERA);
- bool _hasFeatureCameraAutoFocus(Iterable<_XmlElement> features) =>
+ bool _hasFeatureCameraAutoFocus(Iterable<XmlElement> features) =>
features.any((f) =>
f.attributes[ANDROID_NAME]?.value ==
HARDWARE_FEATURE_CAMERA_AUTOFOCUS);
/// Report an error for the given node.
- void _reportErrorForNode(ErrorReporter reporter, _XmlElement node,
- String? key, ErrorCode errorCode,
+ void _reportErrorForNode(
+ ErrorReporter reporter, XmlElement node, String? key, ErrorCode errorCode,
[List<Object>? arguments]) {
var span =
key == null ? node.sourceSpan! : node.attributes[key]!.sourceSpan;
@@ -458,7 +470,7 @@
}
/// Validate the 'activity' tags.
- void _validateActivity(_XmlElement activity, ErrorReporter reporter) {
+ void _validateActivity(XmlElement activity, ErrorReporter reporter) {
var attributes = activity.attributes;
if (attributes.containsKey(ATTRIBUTE_SCREEN_ORIENTATION)) {
if (UNSUPPORTED_ORIENTATIONS
@@ -477,7 +489,7 @@
/// Validate the `uses-feature` tags.
void _validateFeatures(
- Iterable<_XmlElement> features, ErrorReporter reporter) {
+ Iterable<XmlElement> features, ErrorReporter reporter) {
var unsupported = features.where((element) => UNSUPPORTED_HARDWARE_FEATURES
.contains(element.attributes[ANDROID_NAME]?.value));
for (var element in unsupported) {
@@ -510,8 +522,8 @@
}
/// Validate the `uses-permission` tags.
- void _validatePermissions(Iterable<_XmlElement> permissions,
- Iterable<_XmlElement> features, ErrorReporter reporter) {
+ void _validatePermissions(Iterable<XmlElement> permissions,
+ Iterable<XmlElement> features, ErrorReporter reporter) {
for (var permission in permissions) {
if (permission.attributes[ANDROID_NAME]?.value ==
ANDROID_PERMISSION_CAMERA) {
@@ -536,8 +548,8 @@
}
/// Validate the presence/absence of the touchscreen feature tag.
- void _validateTouchScreenFeature(Iterable<_XmlElement> features,
- _XmlElement manifest, ErrorReporter reporter) {
+ void _validateTouchScreenFeature(Iterable<XmlElement> features,
+ XmlElement manifest, ErrorReporter reporter) {
var feature = features.firstWhereOrNull((element) =>
element.attributes[ANDROID_NAME]?.value ==
HARDWARE_FEATURE_TOUCHSCREEN);
@@ -571,7 +583,7 @@
final ParseResult parseResult;
- final Map<String, _XmlAttribute>? attributes;
+ final Map<String, XmlAttribute>? attributes;
ParseAttributeResult(this.parseResult, this.attributes);
}
@@ -596,18 +608,34 @@
relevantElement,
}
-@visibleForTesting
class ParseTagResult {
static ParseTagResult eof = ParseTagResult(ParseResult.eof, null);
static ParseTagResult error = ParseTagResult(ParseResult.error, null);
final ParseResult parseResult;
- final _XmlElement? element;
+ final XmlElement? element;
ParseTagResult(this.parseResult, this.element);
}
+class XmlAttribute {
+ final String name;
+ final String value;
+ final SourceSpan sourceSpan;
+
+ XmlAttribute(this.name, this.value, this.sourceSpan);
+}
+
+class XmlElement {
+ final String name;
+ final Map<String, XmlAttribute> attributes;
+ final List<XmlElement> children;
+ final SourceSpan? sourceSpan;
+
+ XmlElement(this.name, this.attributes, this.children, this.sourceSpan);
+}
+
enum _TagClosingState {
// Represents that the tag's close has not been parsed.
notClosed,
@@ -617,20 +645,3 @@
// an empty element, as per https://www.w3.org/TR/xml/#sec-starttags.
closedEmptyElement,
}
-
-class _XmlAttribute {
- final String name;
- final String value;
- final SourceSpan sourceSpan;
-
- _XmlAttribute(this.name, this.value, this.sourceSpan);
-}
-
-class _XmlElement {
- final String name;
- final Map<String, _XmlAttribute> attributes;
- final List<_XmlElement> children;
- final SourceSpan? sourceSpan;
-
- _XmlElement(this.name, this.attributes, this.children, this.sourceSpan);
-}
diff --git a/pkg/analyzer/test/src/manifest/manifest_validator_test.dart b/pkg/analyzer/test/src/manifest/manifest_validator_test.dart
index a3f0cc1..c9782c9 100644
--- a/pkg/analyzer/test/src/manifest/manifest_validator_test.dart
+++ b/pkg/analyzer/test/src/manifest/manifest_validator_test.dart
@@ -375,7 +375,7 @@
expect(result.element!.name, MANIFEST_TAG);
var sourceSpan = result.element!.sourceSpan!;
expect(sourceSpan.start.offset, equals(0));
- expect(sourceSpan.end.offset, equals(10));
+ expect(sourceSpan.end.offset, equals(11));
}
void test_relevantTag_emptyElement_whitespace_nameIsParsed() {
@@ -384,7 +384,7 @@
expect(result.element!.name, MANIFEST_TAG);
var sourceSpan = result.element!.sourceSpan!;
expect(sourceSpan.start.offset, equals(0));
- expect(sourceSpan.end.offset, equals(11));
+ expect(sourceSpan.end.offset, equals(12));
}
void test_relevantTag_withAttributes_emptyElement_nameIsParsed() {
@@ -393,7 +393,7 @@
expect(result.element!.name, MANIFEST_TAG);
var sourceSpan = result.element!.sourceSpan!;
expect(sourceSpan.start.offset, equals(0));
- expect(sourceSpan.end.offset, equals(21));
+ expect(sourceSpan.end.offset, equals(22));
}
void test_relevantTag_withAttributes_nameIsParsed() {
@@ -403,7 +403,7 @@
expect(result.element!.name, MANIFEST_TAG);
var sourceSpan = result.element!.sourceSpan!;
expect(sourceSpan.start.offset, equals(0));
- expect(sourceSpan.end.offset, equals(30));
+ expect(sourceSpan.end.offset, equals(31));
}
void test_tagBeginningWithWhitespace_isError() {
diff --git a/pkg/analyzer_plugin/doc/api.html b/pkg/analyzer_plugin/doc/api.html
index 859796d..3427f3f 100644
--- a/pkg/analyzer_plugin/doc/api.html
+++ b/pkg/analyzer_plugin/doc/api.html
@@ -1,4 +1,5 @@
-<!DOCTYPE html><html><head>
+<!DOCTYPE html><html>
+<head>
<meta charset="UTF-8">
<title>Analysis Server Plugin API Specification</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Code+Pro|Roboto:500,400italic,300,400" type="text/css"><style>body {
@@ -2427,6 +2428,5 @@
</dd></dl></dd></dl>
<h2 class="domain"><a name="index">Index</a></h2>
<h3>Domains</h3><h4>plugin (<a href="#domain_plugin">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_plugin.versionCheck">versionCheck</a></li><li><a href="#request_plugin.shutdown">shutdown</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_plugin.error">error</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.handleWatchEvents">handleWatchEvents</a></li><li><a href="#request_analysis.setContextRoots">setContextRoots</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li></ul></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getFixes">getFixes</a></li></ul></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextRoot">ContextRoot</a></li><li><a href="#type_DiagnosticMessage">DiagnosticMessage</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_KytheEntry">KytheEntry</a></li><li><a href="#type_KytheVName">KytheVName</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PrioritizedSourceChange">PrioritizedSourceChange</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_WatchEvent">WatchEvent</a></li><li><a href="#type_WatchEventType">WatchEventType</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
-
-
-</body></html>
\ No newline at end of file
+</body>
+</html>
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
index c3322ed..11bb975 100644
--- a/pkg/analyzer_plugin/pubspec.yaml
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -19,7 +19,6 @@
# See also https://dart.dev/tools/pub/dependencies.
dev_dependencies:
analyzer_utilities: any
- html: any
meta: any
path: any
test_reflective_loader: any
diff --git a/pkg/analyzer_plugin/tool/spec/api.dart b/pkg/analyzer_plugin/tool/spec/api.dart
index 04ef8d8..78a086b 100644
--- a/pkg/analyzer_plugin/tool/spec/api.dart
+++ b/pkg/analyzer_plugin/tool/spec/api.dart
@@ -6,7 +6,7 @@
/// for visiting those data structures.
import 'dart:collection';
-import 'package:html/dom.dart' as dom;
+import 'package:analyzer_utilities/html_dom.dart' as dom;
/// Toplevel container for the API.
class Api extends ApiNode {
diff --git a/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart b/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart
index e99476e..b968c7b 100644
--- a/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart
+++ b/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart
@@ -4,8 +4,8 @@
import 'dart:convert';
+import 'package:analyzer_utilities/html_dom.dart' as dom;
import 'package:analyzer_utilities/tools.dart';
-import 'package:html/dom.dart' as dom;
import 'package:path/path.dart' as path;
import 'api.dart';
diff --git a/pkg/analyzer_plugin/tool/spec/from_html.dart b/pkg/analyzer_plugin/tool/spec/from_html.dart
index 53dc875..d5351a2 100644
--- a/pkg/analyzer_plugin/tool/spec/from_html.dart
+++ b/pkg/analyzer_plugin/tool/spec/from_html.dart
@@ -5,9 +5,8 @@
/// Code for reading an HTML API description.
import 'dart:io';
-import 'package:analyzer_utilities/html.dart';
-import 'package:html/dom.dart' as dom;
-import 'package:html/parser.dart' as parser;
+import 'package:analyzer_utilities/html_dom.dart' as dom;
+import 'package:analyzer_utilities/html_generator.dart';
import 'package:path/path.dart';
import 'api.dart';
@@ -114,7 +113,7 @@
throw Exception(
'$context: Unexpected attribute in ${element.localName}: $name');
}
- attributesFound.add(name as String);
+ attributesFound.add(name);
});
for (var expectedAttribute in requiredAttributes) {
if (!attributesFound.contains(expectedAttribute)) {
@@ -292,8 +291,9 @@
/// Read the API description from file with the given [filePath].
Api readApi() {
- var htmlContents = File(filePath).readAsStringSync();
- var document = parser.parse(htmlContents);
+ var file = File(filePath);
+ var htmlContents = file.readAsStringSync();
+ var document = dom.parse(htmlContents, file.uri);
var htmlElement = document.children
.singleWhere((element) => element.localName?.toLowerCase() == 'html');
return apiFromHtml(htmlElement);
diff --git a/pkg/analyzer_plugin/tool/spec/to_html.dart b/pkg/analyzer_plugin/tool/spec/to_html.dart
index 852a05f..84b59f8 100644
--- a/pkg/analyzer_plugin/tool/spec/to_html.dart
+++ b/pkg/analyzer_plugin/tool/spec/to_html.dart
@@ -7,9 +7,9 @@
/// in generated code.
import 'dart:convert';
-import 'package:analyzer_utilities/html.dart';
+import 'package:analyzer_utilities/html_dom.dart' as dom;
+import 'package:analyzer_utilities/html_generator.dart';
import 'package:analyzer_utilities/tools.dart';
-import 'package:html/dom.dart' as dom;
import 'api.dart';
import 'from_html.dart';
@@ -127,7 +127,6 @@
GeneratedFile('doc/api.html', (String pkgPath) async {
var visitor = ToHtmlVisitor(readApi(pkgPath));
var document = dom.Document();
- document.append(dom.DocumentType('html', null, null));
for (var node in visitor.collectHtml(visitor.visitApi)) {
document.append(node);
}
@@ -169,7 +168,7 @@
void dl(void Function() callback) => element('dl', {}, callback);
void dt(String cls, void Function() callback) =>
element('dt', {'class': cls}, callback);
- void element(String name, Map<Object, String> attributes,
+ void element(String name, Map<String, String> attributes,
[void Function()? callback]);
void gray(void Function() callback) =>
element('span', {'style': 'color:#999999'}, callback);
@@ -191,7 +190,7 @@
void i(void Function() callback) => element('i', {}, callback);
void li(void Function() callback) => element('li', {}, callback);
void link(String id, void Function() callback,
- [Map<Object, String>? attributes]) {
+ [Map<String, String>? attributes]) {
attributes ??= {};
attributes['href'] = '#$id';
element('a', attributes, callback);
diff --git a/pkg/analyzer_utilities/lib/html_dom.dart b/pkg/analyzer_utilities/lib/html_dom.dart
new file mode 100644
index 0000000..64fa9b6
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/html_dom.dart
@@ -0,0 +1,182 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+/// A lightweight html parser and DOM model.
+
+import 'dart:convert';
+
+// ignore: implementation_imports
+import 'package:analyzer/src/manifest/manifest_validator.dart';
+
+const _htmlEscape = HtmlEscape(HtmlEscapeMode.element);
+
+abstract class Node {
+ Element? parent;
+
+ final List<Node> nodes = [];
+}
+
+class Element extends Node {
+ String name;
+
+ Map<String, String> attributes = {};
+
+ List<Element> get children => nodes.whereType<Element>().toList();
+
+ Element.tag(this.name);
+
+ // This is for compatibility with the package:html DOM API.
+ String? get localName => name;
+
+ void append(Node child) {
+ child.parent = this;
+ nodes.add(child);
+ }
+
+ List<String> get classes {
+ final classes = attributes['class'];
+ if (classes != null) {
+ return classes.split(' ').toList();
+ } else {
+ return const [];
+ }
+ }
+}
+
+class Text extends Node {
+ static final RegExp tagRegex = RegExp(r'<[^>]+>');
+
+ final String text;
+
+ Text(this.text);
+
+ @override
+ List<Node> get nodes => const [];
+
+ String get textRemoveTags {
+ return text.replaceAll(tagRegex, '');
+ }
+}
+
+class Document extends Element {
+ static const Set<String> selfClosing = {
+ 'br',
+ 'link',
+ 'meta',
+ };
+
+ Document() : super.tag('');
+
+ /// Return the full HTML text for the document.
+ String get outerHtml {
+ var buf = StringBuffer();
+
+ void emitNode(Node node) {
+ if (node is Element) {
+ buf.write('<${node.name}');
+ for (var attr in node.attributes.keys) {
+ buf.write(' $attr="${node.attributes[attr]}"');
+ }
+ if (node.nodes.length == 1 &&
+ node.nodes.first is Text &&
+ !(node.nodes.first as Text).text.contains('\n')) {
+ buf.write('>');
+ var text = node.nodes.first as Text;
+ buf.write(_htmlEscape.convert(text.text));
+ buf.write('</${node.name}>');
+ } else {
+ buf.write('>');
+ for (var child in node.nodes) {
+ emitNode(child);
+ }
+ if (!selfClosing.contains(node.name)) {
+ buf.write('</${node.name}>');
+ }
+ }
+ } else if (node is Text) {
+ buf.write(_htmlEscape.convert(node.text));
+ } else {
+ throw 'unknown node type: $node';
+ }
+ }
+
+ buf.write('<!DOCTYPE html>');
+
+ for (var child in nodes) {
+ emitNode(child);
+ }
+
+ buf.writeln();
+
+ return buf.toString();
+ }
+}
+
+/// Given HTML text, return a parsed HTML tree.
+Document parse(String htmlContents, Uri uri) {
+ final RegExp commentRegex = RegExp(r'<!--[^>]+-->');
+
+ Element createElement(XmlElement xmlElement) {
+ // element
+ var element = Element.tag(xmlElement.name);
+
+ // attributes
+ for (var key in xmlElement.attributes.keys) {
+ element.attributes[key] = xmlElement.attributes[key]!.value;
+ }
+
+ // From the immediate children, determine where the text between the tags is
+ // report any such non empty text as Text nodes.
+ var text = xmlElement.sourceSpan?.text ?? '';
+
+ if (!text.endsWith('/>')) {
+ var indices = <int>[];
+ var offset = xmlElement.sourceSpan!.start.offset;
+
+ indices.add(text.indexOf('>') + 1);
+ for (var child in xmlElement.children) {
+ var childSpan = child.sourceSpan!;
+ indices.add(childSpan.start.offset - offset);
+ indices.add(childSpan.end.offset - offset);
+ }
+ indices.add(text.lastIndexOf('<'));
+
+ var textNodes = <Text>[];
+ for (var index = 0; index < indices.length; index += 2) {
+ var start = indices[index];
+ var end = indices[index + 1];
+ // Remove html comments (<!-- -->) from text.
+ textNodes.add(
+ Text(text.substring(start, end).replaceAll(commentRegex, '')),
+ );
+ }
+
+ element.append(textNodes.removeAt(0));
+
+ for (var child in xmlElement.children) {
+ element.append(createElement(child));
+ element.append(textNodes.removeAt(0));
+ }
+
+ element.nodes.removeWhere((node) => node is Text && node.text.isEmpty);
+ }
+
+ return element;
+ }
+
+ var parser = ManifestParser.general(htmlContents, uri: uri);
+ var result = parser.parseXmlTag();
+
+ while (result.parseResult != ParseTagResult.eof.parseResult) {
+ if (result.element != null) {
+ var document = Document();
+ document.append(createElement(result.element!));
+ return document;
+ }
+
+ result = parser.parseXmlTag();
+ }
+
+ throw 'parse error - element not found';
+}
diff --git a/pkg/analyzer_utilities/lib/html.dart b/pkg/analyzer_utilities/lib/html_generator.dart
similarity index 88%
rename from pkg/analyzer_utilities/lib/html.dart
rename to pkg/analyzer_utilities/lib/html_generator.dart
index c5dc4bf..c7aed6b 100644
--- a/pkg/analyzer_utilities/lib/html.dart
+++ b/pkg/analyzer_utilities/lib/html_generator.dart
@@ -4,11 +4,8 @@
/// Tools for manipulating HTML during code generation of analyzer and analysis
/// server.
-import 'package:html/dom.dart' as dom;
-/// Make a deep copy of the given HTML nodes.
-List<dom.Node> cloneHtmlNodes(List<dom.Node> nodes) =>
- nodes.map((dom.Node node) => node.clone(true)).toList();
+import 'html_dom.dart' as dom;
/// Return true if the given iterable contains only whitespace text nodes.
bool containsOnlyWhitespace(Iterable<dom.Node> nodes) {
@@ -26,7 +23,7 @@
void recurse(dom.Element parent) {
for (var child in parent.nodes) {
if (child is dom.Text) {
- buffer.write(child.text);
+ buffer.write(child.textRemoveTags);
} else if (child is dom.Element) {
recurse(child);
}
@@ -51,7 +48,7 @@
/// Create an HTML element with the given name, attributes, and child nodes.
dom.Element makeElement(
- String name, Map<Object, String> attributes, List<dom.Node> children) {
+ String name, Map<String, String> attributes, List<dom.Node> children) {
var result = dom.Element.tag(name);
result.attributes.addAll(attributes);
for (var child in children) {
@@ -94,7 +91,7 @@
/// Execute [callback], wrapping its output in an element with the given
/// [name] and [attributes].
- void element(String name, Map<Object, String> attributes,
+ void element(String name, Map<String, String> attributes,
[void Function()? callback]) {
add(makeElement(name, attributes, collectHtml(callback)));
}
diff --git a/pkg/analyzer_utilities/lib/text_formatter.dart b/pkg/analyzer_utilities/lib/text_formatter.dart
index 79c92d2..ce20d49 100644
--- a/pkg/analyzer_utilities/lib/text_formatter.dart
+++ b/pkg/analyzer_utilities/lib/text_formatter.dart
@@ -4,8 +4,8 @@
/// Code for converting HTML into text, for use during code generation of
/// analyzer and analysis server.
+import 'package:analyzer_utilities/html_dom.dart' as dom;
import 'package:analyzer_utilities/tools.dart';
-import 'package:html/dom.dart' as dom;
final RegExp whitespace = RegExp(r'\s');
@@ -83,6 +83,7 @@
lineBreak(false);
if (node.classes.contains('hangingIndent')) {
resolveVerticalSpace();
+ // TODO(devoncarew): Remove a space here.
indentSpecial('', ' ', () {
addAll(node.nodes);
lineBreak(false);
diff --git a/pkg/analyzer_utilities/lib/tools.dart b/pkg/analyzer_utilities/lib/tools.dart
index c1a5ca7..79f022c 100644
--- a/pkg/analyzer_utilities/lib/tools.dart
+++ b/pkg/analyzer_utilities/lib/tools.dart
@@ -6,9 +6,9 @@
import 'dart:async';
import 'dart:io';
-import 'package:analyzer_utilities/html.dart';
+import 'package:analyzer_utilities/html_dom.dart' as dom;
+import 'package:analyzer_utilities/html_generator.dart';
import 'package:analyzer_utilities/text_formatter.dart';
-import 'package:html/dom.dart' as dom;
import 'package:path/path.dart';
import 'package:test/test.dart';
@@ -473,7 +473,7 @@
/// Execute [callback], wrapping its output in an element with the given
/// [name] and [attributes].
- void element(String name, Map<Object, String> attributes,
+ void element(String name, Map<String, String> attributes,
[void Function()? callback]) {
add(makeElement(name, attributes, collectHtml(callback)));
}
diff --git a/pkg/analyzer_utilities/pubspec.yaml b/pkg/analyzer_utilities/pubspec.yaml
index a7c634c..f803290 100644
--- a/pkg/analyzer_utilities/pubspec.yaml
+++ b/pkg/analyzer_utilities/pubspec.yaml
@@ -8,7 +8,6 @@
# Use 'any' constraints here; we get our versions from the DEPS file.
dependencies:
analyzer: any
- html: any
meta: any
path: any
test: any
diff --git a/tools/VERSION b/tools/VERSION
index dae6e49..f2b2239 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 228
+PRERELEASE 229
PRERELEASE_PATCH 0
\ No newline at end of file