Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Unified Diff: pkg/analyzer_plugin/tool/spec/api.dart

Issue 2664213003: Add the generator and the generated files (Closed)
Patch Set: add missed files Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer_plugin/tool/spec/api.dart
diff --git a/pkg/analyzer_plugin/tool/spec/api.dart b/pkg/analyzer_plugin/tool/spec/api.dart
new file mode 100644
index 0000000000000000000000000000000000000000..0c73c8880f14926b9df15f4c14d45bbe5a622564
--- /dev/null
+++ b/pkg/analyzer_plugin/tool/spec/api.dart
@@ -0,0 +1,514 @@
+// Copyright (c) 2017, 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.
+
+/**
+ * Data structures representing an API definition, and visitor base classes
+ * for visiting those data structures.
+ */
+import 'dart:collection';
+
+import 'package:html/dom.dart' as dom;
+
+/**
+ * Toplevel container for the API.
+ */
+class Api extends ApiNode {
+ final String version;
+ final List<Domain> domains;
+ final Types types;
+ final Refactorings refactorings;
+
+ Api(this.version, this.domains, this.types, this.refactorings,
+ dom.Element html,
+ {bool experimental})
+ : super(html, experimental);
+}
+
+/**
+ * Base class for objects in the API model.
+ */
+class ApiNode {
+ /**
+ * A flag to indicate if this API is experimental.
+ */
+ final bool experimental;
+
+ /**
+ * Html element representing this part of the API.
+ */
+ final dom.Element html;
+
+ ApiNode(this.html, bool experimental)
+ : this.experimental = experimental ?? false;
+}
+
+/**
+ * Base class for visiting the API definition.
+ */
+abstract class ApiVisitor<T> {
+ /**
+ * Dispatch the given [type] to the visitor.
+ */
+ T visitTypeDecl(TypeDecl type) => type.accept(this) as T;
+ T visitTypeEnum(TypeEnum typeEnum);
+ T visitTypeList(TypeList typeList);
+ T visitTypeMap(TypeMap typeMap);
+ T visitTypeObject(TypeObject typeObject);
+ T visitTypeReference(TypeReference typeReference);
+
+ T visitTypeUnion(TypeUnion typeUnion);
+}
+
+/**
+ * Definition of a single domain.
+ */
+class Domain extends ApiNode {
+ final String name;
+ final List<Request> requests;
+ final List<Notification> notifications;
+
+ Domain(this.name, this.requests, this.notifications, dom.Element html,
+ {bool experimental})
+ : super(html, experimental);
+}
+
+/**
+ * API visitor that visits the entire API hierarchically by default.
+ */
+class HierarchicalApiVisitor extends ApiVisitor {
+ /**
+ * The API to visit.
+ */
+ final Api api;
+
+ HierarchicalApiVisitor(this.api);
+
+ /**
+ * If [type] is a [TypeReference] that is defined in the API, follow the
+ * chain until a non-[TypeReference] is found, if possible.
+ *
+ * If it is not possible (because the chain ends with a [TypeReference] that
+ * is not defined in the API), then that final [TypeReference] is returned.
+ */
+ TypeDecl resolveTypeReferenceChain(TypeDecl type) {
+ while (type is TypeReference && api.types.containsKey(type.typeName)) {
+ type = api.types[(type as TypeReference).typeName].type;
+ }
+ return type;
+ }
+
+ void visitApi() {
+ api.domains.forEach(visitDomain);
+ visitTypes(api.types);
+ visitRefactorings(api.refactorings);
+ }
+
+ void visitDomain(Domain domain) {
+ domain.requests.forEach(visitRequest);
+ domain.notifications.forEach(visitNotification);
+ }
+
+ void visitNotification(Notification notification) {
+ if (notification.params != null) {
+ visitTypeDecl(notification.params);
+ }
+ }
+
+ void visitRefactoring(Refactoring refactoring) {
+ if (refactoring.feedback != null) {
+ visitTypeDecl(refactoring.feedback);
+ }
+ if (refactoring.options != null) {
+ visitTypeDecl(refactoring.options);
+ }
+ }
+
+ void visitRefactorings(Refactorings refactorings) {
+ refactorings?.forEach(visitRefactoring);
+ }
+
+ void visitRequest(Request request) {
+ if (request.params != null) {
+ visitTypeDecl(request.params);
+ }
+ if (request.result != null) {
+ visitTypeDecl(request.result);
+ }
+ }
+
+ void visitTypeDefinition(TypeDefinition typeDefinition) {
+ visitTypeDecl(typeDefinition.type);
+ }
+
+ @override
+ void visitTypeEnum(TypeEnum typeEnum) {
+ typeEnum.values.forEach(visitTypeEnumValue);
+ }
+
+ void visitTypeEnumValue(TypeEnumValue typeEnumValue) {}
+
+ @override
+ void visitTypeList(TypeList typeList) {
+ visitTypeDecl(typeList.itemType);
+ }
+
+ @override
+ void visitTypeMap(TypeMap typeMap) {
+ visitTypeDecl(typeMap.keyType);
+ visitTypeDecl(typeMap.valueType);
+ }
+
+ @override
+ void visitTypeObject(TypeObject typeObject) {
+ typeObject.fields.forEach(visitTypeObjectField);
+ }
+
+ void visitTypeObjectField(TypeObjectField typeObjectField) {
+ visitTypeDecl(typeObjectField.type);
+ }
+
+ @override
+ void visitTypeReference(TypeReference typeReference) {}
+
+ void visitTypes(Types types) {
+ types.forEach(visitTypeDefinition);
+ }
+
+ @override
+ void visitTypeUnion(TypeUnion typeUnion) {
+ typeUnion.choices.forEach(visitTypeDecl);
+ }
+}
+
+/**
+ * Description of a notification method.
+ */
+class Notification extends ApiNode {
+ /**
+ * Name of the domain enclosing this request.
+ */
+ final String domainName;
+
+ /**
+ * Name of the notification, without the domain prefix.
+ */
+ final String event;
+
+ /**
+ * Type of the object associated with the "params" key in the notification
+ * object, or null if the notification has no parameters.
+ */
+ final TypeObject params;
+
+ Notification(this.domainName, this.event, this.params, dom.Element html,
+ {bool experimental})
+ : super(html, experimental);
+
+ /**
+ * Get the name of the notification, including the domain prefix.
+ */
+ String get longEvent => '$domainName.$event';
+
+ /**
+ * Get the full type of the notification object, including the common "id"
+ * and "error" fields.
+ */
+ TypeDecl get notificationType {
+ List<TypeObjectField> fields = [
+ new TypeObjectField('event', new TypeReference('String', null), null,
+ value: '$domainName.$event')
+ ];
+ if (params != null) {
+ fields.add(new TypeObjectField('params', params, null));
+ }
+ return new TypeObject(fields, null);
+ }
+}
+
+/**
+ * Description of a single refactoring.
+ */
+class Refactoring extends ApiNode {
+ /**
+ * Name of the refactoring. This should match one of the values allowed for
+ * RefactoringKind.
+ */
+ final String kind;
+
+ /**
+ * Type of the refactoring feedback, or null if the refactoring has no
+ * feedback.
+ */
+ final TypeObject feedback;
+
+ /**
+ * Type of the refactoring options, or null if the refactoring has no options.
+ */
+ final TypeObject options;
+
+ Refactoring(this.kind, this.feedback, this.options, dom.Element html,
+ {bool experimental})
+ : super(html, experimental);
+}
+
+/**
+ * A collection of refactoring definitions.
+ */
+class Refactorings extends ApiNode with IterableMixin<Refactoring> {
+ final List<Refactoring> refactorings;
+
+ Refactorings(this.refactorings, dom.Element html, {bool experimental})
+ : super(html, experimental);
+
+ @override
+ Iterator<Refactoring> get iterator => refactorings.iterator;
+}
+
+/**
+ * Description of a request method.
+ */
+class Request extends ApiNode {
+ /**
+ * Name of the domain enclosing this request.
+ */
+ final String domainName;
+
+ /**
+ * Name of the request, without the domain prefix.
+ */
+ final String method;
+
+ /**
+ * Type of the object associated with the "params" key in the request object,
+ * or null if the request has no parameters.
+ */
+ final TypeObject params;
+
+ /**
+ * Type of the object associated with the "result" key in the response object,
+ * or null if the response has no results.
+ */
+ final TypeObject result;
+
+ Request(
+ this.domainName, this.method, this.params, this.result, dom.Element html,
+ {bool experimental})
+ : super(html, experimental);
+
+ /**
+ * Get the name of the request, including the domain prefix.
+ */
+ String get longMethod => '$domainName.$method';
+
+ /**
+ * Get the full type of the request object, including the common "id" and
+ * "method" fields.
+ */
+ TypeDecl get requestType {
+ List<TypeObjectField> fields = [
+ new TypeObjectField('id', new TypeReference('String', null), null),
+ new TypeObjectField('method', new TypeReference('String', null), null,
+ value: '$domainName.$method')
+ ];
+ if (params != null) {
+ fields.add(new TypeObjectField('params', params, null));
+ }
+ return new TypeObject(fields, null);
+ }
+
+ /**
+ * Get the full type of the response object, including the common "id" and
+ * "error" fields.
+ */
+ TypeDecl get responseType {
+ List<TypeObjectField> fields = [
+ new TypeObjectField('id', new TypeReference('String', null), null),
+ new TypeObjectField(
+ 'error', new TypeReference('RequestError', null), null,
+ optional: true)
+ ];
+ if (result != null) {
+ fields.add(new TypeObjectField('result', result, null));
+ }
+ return new TypeObject(fields, null);
+ }
+}
+
+/**
+ * Base class for all possible types.
+ */
+abstract class TypeDecl extends ApiNode {
+ TypeDecl(dom.Element html, bool experimental) : super(html, experimental);
+
+ accept(ApiVisitor visitor);
+}
+
+/**
+ * Description of a named type definition.
+ */
+class TypeDefinition extends ApiNode {
+ final String name;
+ final TypeDecl type;
+
+ TypeDefinition(this.name, this.type, dom.Element html, {bool experimental})
+ : super(html, experimental);
+}
+
+/**
+ * Type of an enum. We represent enums in JSON as strings, so this type
+ * declaration simply lists the allowed values.
+ */
+class TypeEnum extends TypeDecl {
+ final List<TypeEnumValue> values;
+
+ TypeEnum(this.values, dom.Element html, {bool experimental})
+ : super(html, experimental);
+
+ @override
+ accept(ApiVisitor visitor) => visitor.visitTypeEnum(this);
+}
+
+/**
+ * Description of a single allowed value for an enum.
+ */
+class TypeEnumValue extends ApiNode {
+ final String value;
+
+ TypeEnumValue(this.value, dom.Element html, {bool experimental})
+ : super(html, experimental);
+}
+
+/**
+ * Type of a JSON list.
+ */
+class TypeList extends TypeDecl {
+ final TypeDecl itemType;
+
+ TypeList(this.itemType, dom.Element html, {bool experimental})
+ : super(html, experimental);
+
+ @override
+ accept(ApiVisitor visitor) => visitor.visitTypeList(this);
+}
+
+/**
+ * Type of a JSON map.
+ */
+class TypeMap extends TypeDecl {
+ /**
+ * Type of map keys. Note that since JSON map keys must always be strings,
+ * this must either be a [TypeReference] for [String], or a [TypeReference]
+ * to a type which is defined in the API as an enum or a synonym for [String].
+ */
+ final TypeReference keyType;
+
+ /**
+ * Type of map values.
+ */
+ final TypeDecl valueType;
+
+ TypeMap(this.keyType, this.valueType, dom.Element html, {bool experimental})
+ : super(html, experimental);
+
+ @override
+ accept(ApiVisitor visitor) => visitor.visitTypeMap(this);
+}
+
+/**
+ * Type of a JSON object with specified fields, some of which may be optional.
+ */
+class TypeObject extends TypeDecl {
+ final List<TypeObjectField> fields;
+
+ TypeObject(this.fields, dom.Element html, {bool experimental})
+ : super(html, experimental);
+
+ @override
+ accept(ApiVisitor visitor) => visitor.visitTypeObject(this);
+
+ /**
+ * Return the field with the given [name], or null if there is no such field.
+ */
+ TypeObjectField getField(String name) {
+ for (TypeObjectField field in fields) {
+ if (field.name == name) {
+ return field;
+ }
+ }
+ return null;
+ }
+}
+
+/**
+ * Description of a single field in a [TypeObject].
+ */
+class TypeObjectField extends ApiNode {
+ final String name;
+ final TypeDecl type;
+ final bool optional;
+
+ /**
+ * Value that the field is required to contain, or null if it may vary.
+ */
+ final Object value;
+
+ TypeObjectField(this.name, this.type, dom.Element html,
+ {this.optional: false, this.value, bool experimental})
+ : super(html, experimental);
+}
+
+/**
+ * A reference to a type which is either defined elsewhere in the API or which
+ * is built-in ([String], [bool], or [int]).
+ */
+class TypeReference extends TypeDecl {
+ final String typeName;
+
+ TypeReference(this.typeName, dom.Element html, {bool experimental})
+ : super(html, experimental) {
+ if (typeName.isEmpty) {
+ throw new Exception('Empty type name');
+ }
+ }
+
+ @override
+ accept(ApiVisitor visitor) => visitor.visitTypeReference(this);
+}
+
+/**
+ * A collection of type definitions.
+ */
+class Types extends ApiNode with IterableMixin<TypeDefinition> {
+ final Map<String, TypeDefinition> types;
+
+ Types(this.types, dom.Element html, {bool experimental})
+ : super(html, experimental);
+
+ @override
+ Iterator<TypeDefinition> get iterator => types.values.iterator;
+
+ Iterable<String> get keys => types.keys;
+
+ TypeDefinition operator [](String typeName) => types[typeName];
+
+ bool containsKey(String typeName) => types.containsKey(typeName);
+}
+
+/**
+ * Type which represents a union among multiple choices.
+ */
+class TypeUnion extends TypeDecl {
+ final List<TypeDecl> choices;
+
+ /**
+ * The field that is used to disambiguate this union
+ */
+ final String field;
+
+ TypeUnion(this.choices, this.field, dom.Element html, {bool experimental})
+ : super(html, experimental);
+
+ @override
+ accept(ApiVisitor visitor) => visitor.visitTypeUnion(this);
+}
« no previous file with comments | « pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart ('k') | pkg/analyzer_plugin/tool/spec/check_all_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698