Implement fromJson() constructors for LSP types
Also add a canParse() method that can check whether some provided JSON can be decoded into that type (used for detecting with type from a union to decode as).
Support equality checks on unions and a valueEquals() helper
Remove brittle tests that do exact comparisons on generated code
Fix deserialisation of lists to be cast and toList()'d
Add a more complete JSON test that includes lists, enums
Change-Id: Id56fdad9b1454e540e55907e0ff2608263a87c40
Reviewed-on: https://dart-review.googlesource.com/c/80580
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Danny Tuppeny <dantup@google.com>
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
index 7f93e74..97a2721 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
@@ -11,7 +11,16 @@
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
class ApplyWorkspaceEditParams {
- ApplyWorkspaceEditParams(this.label, this.edit);
+ ApplyWorkspaceEditParams(this.label, this.edit) {
+ if (edit == null) {
+ throw 'edit is required but was not provided';
+ }
+ }
+ factory ApplyWorkspaceEditParams.fromJson(Map<String, dynamic> json) {
+ final label = json['label'];
+ final edit = new WorkspaceEdit.fromJson(json['edit']);
+ return new ApplyWorkspaceEditParams(label, edit);
+ }
/// The edits to apply.
final WorkspaceEdit edit;
@@ -28,10 +37,30 @@
__result['edit'] = edit ?? (throw 'edit is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('edit') || !WorkspaceEdit.canParse(map['edit'])) {
+ return false;
+ }
+ const validFieldNames = ['label', 'edit'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ApplyWorkspaceEditResponse {
- ApplyWorkspaceEditResponse(this.applied);
+ ApplyWorkspaceEditResponse(this.applied) {
+ if (applied == null) {
+ throw 'applied is required but was not provided';
+ }
+ }
+ factory ApplyWorkspaceEditResponse.fromJson(Map<String, dynamic> json) {
+ final applied = json['applied'];
+ return new ApplyWorkspaceEditResponse(applied);
+ }
/// Indicates whether the edit was applied or not.
final bool applied;
@@ -42,10 +71,34 @@
applied ?? (throw 'applied is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('applied') || !map['applied'] is bool) {
+ return false;
+ }
+ const validFieldNames = ['applied'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class CancelParams {
- CancelParams(this.id);
+ CancelParams(this.id) {
+ if (id == null) {
+ throw 'id is required but was not provided';
+ }
+ }
+ factory CancelParams.fromJson(Map<String, dynamic> json) {
+ final id = json['id'] is num
+ ? new Either2<num, String>.t1(json['id'])
+ : (json['id'] is String
+ ? new Either2<num, String>.t2(json['id'])
+ : (throw '''${json['id']} was not one of (number, string)'''));
+ return new CancelParams(id);
+ }
/// The request id to cancel.
final Either2<num, String> id;
@@ -55,10 +108,30 @@
__result['id'] = id ?? (throw 'id is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('id') || !(map['id'] is num || map['id'] is String)) {
+ return false;
+ }
+ const validFieldNames = ['id'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ClientCapabilities {
ClientCapabilities(this.workspace, this.textDocument, this.experimental);
+ factory ClientCapabilities.fromJson(Map<String, dynamic> json) {
+ final workspace =
+ new WorkspaceClientCapabilities.fromJson(json['workspace']);
+ final textDocument =
+ new TextDocumentClientCapabilities.fromJson(json['textDocument']);
+ final experimental = json['experimental'];
+ return new ClientCapabilities(workspace, textDocument, experimental);
+ }
/// Experimental client capabilities.
final dynamic experimental;
@@ -82,6 +155,15 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['workspace', 'textDocument', 'experimental'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// A code action represents a change that can be performed in code, e.g. to fix
@@ -90,7 +172,22 @@
/// A CodeAction must set either `edit` and/or a `command`. If both are
/// supplied, the `edit` is applied first, then the `command` is executed.
class CodeAction {
- CodeAction(this.title, this.kind, this.diagnostics, this.edit, this.command);
+ CodeAction(this.title, this.kind, this.diagnostics, this.edit, this.command) {
+ if (title == null) {
+ throw 'title is required but was not provided';
+ }
+ }
+ factory CodeAction.fromJson(Map<String, dynamic> json) {
+ final title = json['title'];
+ final kind = json['kind'];
+ final diagnostics = json['diagnostics']
+ ?.map((item) => new Diagnostic.fromJson(item))
+ ?.cast<Diagnostic>()
+ ?.toList();
+ final edit = new WorkspaceEdit.fromJson(json['edit']);
+ final command = new Command.fromJson(json['command']);
+ return new CodeAction(title, kind, diagnostics, edit, command);
+ }
/// A command this code action executes. If a code action provides an edit and
/// a command, first the edit is executed and then the command.
@@ -127,12 +224,36 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('title') || !map['title'] is String) {
+ return false;
+ }
+ const validFieldNames = ['title', 'kind', 'diagnostics', 'edit', 'command'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Contains additional diagnostic information about the context in which a code
/// action is run.
class CodeActionContext {
- CodeActionContext(this.diagnostics, this.only);
+ CodeActionContext(this.diagnostics, this.only) {
+ if (diagnostics == null) {
+ throw 'diagnostics is required but was not provided';
+ }
+ }
+ factory CodeActionContext.fromJson(Map<String, dynamic> json) {
+ final diagnostics = json['diagnostics']
+ ?.map((item) => new Diagnostic.fromJson(item))
+ ?.cast<Diagnostic>()
+ ?.toList();
+ final only = json['only']?.map((item) => item)?.cast<String>()?.toList();
+ return new CodeActionContext(diagnostics, only);
+ }
/// An array of diagnostics.
final List<Diagnostic> diagnostics;
@@ -152,6 +273,22 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('diagnostics') ||
+ !(map['diagnostics'] is List &&
+ (map['diagnostics'].length == 0 ||
+ map['diagnostics']
+ .every((item) => Diagnostic.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['diagnostics', 'only'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// A set of predefined code action kinds
@@ -207,6 +344,11 @@
/// Code Action options.
class CodeActionOptions {
CodeActionOptions(this.codeActionKinds);
+ factory CodeActionOptions.fromJson(Map<String, dynamic> json) {
+ final codeActionKinds =
+ json['codeActionKinds']?.map((item) => item)?.cast<String>()?.toList();
+ return new CodeActionOptions(codeActionKinds);
+ }
/// CodeActionKinds that this server may return.
///
@@ -221,11 +363,37 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['codeActionKinds'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Params for the CodeActionRequest
class CodeActionParams {
- CodeActionParams(this.textDocument, this.range, this.context);
+ CodeActionParams(this.textDocument, this.range, this.context) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (range == null) {
+ throw 'range is required but was not provided';
+ }
+ if (context == null) {
+ throw 'context is required but was not provided';
+ }
+ }
+ factory CodeActionParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ final range = new Range.fromJson(json['range']);
+ final context = new CodeActionContext.fromJson(json['context']);
+ return new CodeActionParams(textDocument, range, context);
+ }
/// Context carrying additional information.
final CodeActionContext context;
@@ -245,11 +413,40 @@
context ?? (throw 'context is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('range') || !Range.canParse(map['range'])) {
+ return false;
+ }
+ if (!map.containsKey('context') ||
+ !CodeActionContext.canParse(map['context'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument', 'range', 'context'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class CodeActionRegistrationOptions
implements TextDocumentRegistrationOptions, CodeActionOptions {
CodeActionRegistrationOptions(this.documentSelector, this.codeActionKinds);
+ factory CodeActionRegistrationOptions.fromJson(Map<String, dynamic> json) {
+ final documentSelector = json['documentSelector']
+ ?.map((item) => new DocumentFilter.fromJson(item))
+ ?.cast<DocumentFilter>()
+ ?.toList();
+ final codeActionKinds =
+ json['codeActionKinds']?.map((item) => item)?.cast<String>()?.toList();
+ return new CodeActionRegistrationOptions(documentSelector, codeActionKinds);
+ }
/// CodeActionKinds that this server may return.
///
@@ -269,6 +466,22 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('documentSelector') ||
+ !(map['documentSelector'] is List &&
+ (map['documentSelector'].length == 0 ||
+ map['documentSelector']
+ .every((item) => DocumentFilter.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['documentSelector', 'codeActionKinds'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// A code lens represents a command that should be shown along with source
@@ -278,7 +491,17 @@
/// performance reasons the creation of a code lens and resolving should be done
/// in two stages.
class CodeLens {
- CodeLens(this.range, this.command, this.data);
+ CodeLens(this.range, this.command, this.data) {
+ if (range == null) {
+ throw 'range is required but was not provided';
+ }
+ }
+ factory CodeLens.fromJson(Map<String, dynamic> json) {
+ final range = new Range.fromJson(json['range']);
+ final command = new Command.fromJson(json['command']);
+ final data = json['data'];
+ return new CodeLens(range, command, data);
+ }
/// The command this code lens represents.
final Command command;
@@ -302,11 +525,27 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('range') || !Range.canParse(map['range'])) {
+ return false;
+ }
+ const validFieldNames = ['range', 'command', 'data'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Code Lens options.
class CodeLensOptions {
CodeLensOptions(this.resolveProvider);
+ factory CodeLensOptions.fromJson(Map<String, dynamic> json) {
+ final resolveProvider = json['resolveProvider'];
+ return new CodeLensOptions(resolveProvider);
+ }
/// Code lens has a resolve provider as well.
final bool resolveProvider;
@@ -318,10 +557,28 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['resolveProvider'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class CodeLensParams {
- CodeLensParams(this.textDocument);
+ CodeLensParams(this.textDocument) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ }
+ factory CodeLensParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ return new CodeLensParams(textDocument);
+ }
/// The document to request code lens for.
final TextDocumentIdentifier textDocument;
@@ -332,10 +589,31 @@
textDocument ?? (throw 'textDocument is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class CodeLensRegistrationOptions implements TextDocumentRegistrationOptions {
CodeLensRegistrationOptions(this.resolveProvider, this.documentSelector);
+ factory CodeLensRegistrationOptions.fromJson(Map<String, dynamic> json) {
+ final resolveProvider = json['resolveProvider'];
+ final documentSelector = json['documentSelector']
+ ?.map((item) => new DocumentFilter.fromJson(item))
+ ?.cast<DocumentFilter>()
+ ?.toList();
+ return new CodeLensRegistrationOptions(resolveProvider, documentSelector);
+ }
/// A document selector to identify the scope of the registration. If set to
/// null the document selector provided on the client side will be used.
@@ -352,11 +630,47 @@
__result['documentSelector'] = documentSelector;
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('documentSelector') ||
+ !(map['documentSelector'] is List &&
+ (map['documentSelector'].length == 0 ||
+ map['documentSelector']
+ .every((item) => DocumentFilter.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['resolveProvider', 'documentSelector'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Represents a color in RGBA space.
class Color {
- Color(this.red, this.green, this.blue, this.alpha);
+ Color(this.red, this.green, this.blue, this.alpha) {
+ if (red == null) {
+ throw 'red is required but was not provided';
+ }
+ if (green == null) {
+ throw 'green is required but was not provided';
+ }
+ if (blue == null) {
+ throw 'blue is required but was not provided';
+ }
+ if (alpha == null) {
+ throw 'alpha is required but was not provided';
+ }
+ }
+ factory Color.fromJson(Map<String, dynamic> json) {
+ final red = json['red'];
+ final green = json['green'];
+ final blue = json['blue'];
+ final alpha = json['alpha'];
+ return new Color(red, green, blue, alpha);
+ }
final num alpha;
final num blue;
@@ -371,10 +685,43 @@
__result['alpha'] = alpha ?? (throw 'alpha is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('red') || !map['red'] is num) {
+ return false;
+ }
+ if (!map.containsKey('green') || !map['green'] is num) {
+ return false;
+ }
+ if (!map.containsKey('blue') || !map['blue'] is num) {
+ return false;
+ }
+ if (!map.containsKey('alpha') || !map['alpha'] is num) {
+ return false;
+ }
+ const validFieldNames = ['red', 'green', 'blue', 'alpha'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ColorInformation {
- ColorInformation(this.range, this.color);
+ ColorInformation(this.range, this.color) {
+ if (range == null) {
+ throw 'range is required but was not provided';
+ }
+ if (color == null) {
+ throw 'color is required but was not provided';
+ }
+ }
+ factory ColorInformation.fromJson(Map<String, dynamic> json) {
+ final range = new Range.fromJson(json['range']);
+ final color = new Color.fromJson(json['color']);
+ return new ColorInformation(range, color);
+ }
/// The actual color value for this color range.
final Color color;
@@ -388,10 +735,38 @@
__result['color'] = color ?? (throw 'color is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('range') || !Range.canParse(map['range'])) {
+ return false;
+ }
+ if (!map.containsKey('color') || !Color.canParse(map['color'])) {
+ return false;
+ }
+ const validFieldNames = ['range', 'color'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ColorPresentation {
- ColorPresentation(this.label, this.textEdit, this.additionalTextEdits);
+ ColorPresentation(this.label, this.textEdit, this.additionalTextEdits) {
+ if (label == null) {
+ throw 'label is required but was not provided';
+ }
+ }
+ factory ColorPresentation.fromJson(Map<String, dynamic> json) {
+ final label = json['label'];
+ final textEdit = new TextEdit.fromJson(json['textEdit']);
+ final additionalTextEdits = json['additionalTextEdits']
+ ?.map((item) => new TextEdit.fromJson(item))
+ ?.cast<TextEdit>()
+ ?.toList();
+ return new ColorPresentation(label, textEdit, additionalTextEdits);
+ }
/// An optional array of additional text edits ([TextEdit]) that are applied
/// when selecting this color presentation. Edits must not overlap with the
@@ -419,10 +794,39 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('label') || !map['label'] is String) {
+ return false;
+ }
+ const validFieldNames = ['label', 'textEdit', 'additionalTextEdits'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ColorPresentationParams {
- ColorPresentationParams(this.textDocument, this.color, this.range);
+ ColorPresentationParams(this.textDocument, this.color, this.range) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (color == null) {
+ throw 'color is required but was not provided';
+ }
+ if (range == null) {
+ throw 'range is required but was not provided';
+ }
+ }
+ factory ColorPresentationParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ final color = new Color.fromJson(json['color']);
+ final range = new Range.fromJson(json['range']);
+ return new ColorPresentationParams(textDocument, color, range);
+ }
/// The color information to request presentations for.
final Color color;
@@ -441,6 +845,25 @@
__result['range'] = range ?? (throw 'range is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('color') || !Color.canParse(map['color'])) {
+ return false;
+ }
+ if (!map.containsKey('range') || !Range.canParse(map['range'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument', 'color', 'range'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Color provider options.
@@ -449,10 +872,33 @@
Map<String, dynamic> __result = {};
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = [''];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class Command {
- Command(this.title, this.command, this.arguments);
+ Command(this.title, this.command, this.arguments) {
+ if (title == null) {
+ throw 'title is required but was not provided';
+ }
+ if (command == null) {
+ throw 'command is required but was not provided';
+ }
+ }
+ factory Command.fromJson(Map<String, dynamic> json) {
+ final title = json['title'];
+ final command = json['command'];
+ final arguments =
+ json['arguments']?.map((item) => item)?.cast<dynamic>()?.toList();
+ return new Command(title, command, arguments);
+ }
/// Arguments that the command handler should be invoked with.
final List<dynamic> arguments;
@@ -473,12 +919,36 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('title') || !map['title'] is String) {
+ return false;
+ }
+ if (!map.containsKey('command') || !map['command'] is String) {
+ return false;
+ }
+ const validFieldNames = ['title', 'command', 'arguments'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Contains additional information about the context in which a completion
/// request is triggered.
class CompletionContext {
- CompletionContext(this.triggerKind, this.triggerCharacter);
+ CompletionContext(this.triggerKind, this.triggerCharacter) {
+ if (triggerKind == null) {
+ throw 'triggerKind is required but was not provided';
+ }
+ }
+ factory CompletionContext.fromJson(Map<String, dynamic> json) {
+ final triggerKind = new CompletionTriggerKind.fromJson(json['triggerKind']);
+ final triggerCharacter = json['triggerCharacter'];
+ return new CompletionContext(triggerKind, triggerCharacter);
+ }
/// The trigger character (a single character) that has trigger code complete.
/// Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
@@ -496,6 +966,19 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('triggerKind') ||
+ !CompletionTriggerKind.canParse(map['triggerKind'])) {
+ return false;
+ }
+ const validFieldNames = ['triggerKind', 'triggerCharacter'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class CompletionItem {
@@ -514,7 +997,54 @@
this.additionalTextEdits,
this.commitCharacters,
this.command,
- this.data);
+ this.data) {
+ if (label == null) {
+ throw 'label is required but was not provided';
+ }
+ }
+ factory CompletionItem.fromJson(Map<String, dynamic> json) {
+ final label = json['label'];
+ final kind = new CompletionItemKind.fromJson(json['kind']);
+ final detail = json['detail'];
+ final documentation = json['documentation'] is String
+ ? new Either2<String, MarkupContent>.t1(json['documentation'])
+ : (MarkupContent.canParse(json['documentation'])
+ ? new Either2<String, MarkupContent>.t2(
+ new MarkupContent.fromJson(json['documentation']))
+ : (throw '''${json['documentation']} was not one of (string, MarkupContent)'''));
+ final deprecated = json['deprecated'];
+ final preselect = json['preselect'];
+ final sortText = json['sortText'];
+ final filterText = json['filterText'];
+ final insertText = json['insertText'];
+ final insertTextFormat =
+ new InsertTextFormat.fromJson(json['insertTextFormat']);
+ final textEdit = new TextEdit.fromJson(json['textEdit']);
+ final additionalTextEdits = json['additionalTextEdits']
+ ?.map((item) => new TextEdit.fromJson(item))
+ ?.cast<TextEdit>()
+ ?.toList();
+ final commitCharacters =
+ json['commitCharacters']?.map((item) => item)?.cast<String>()?.toList();
+ final command = new Command.fromJson(json['command']);
+ final data = json['data'];
+ return new CompletionItem(
+ label,
+ kind,
+ detail,
+ documentation,
+ deprecated,
+ preselect,
+ sortText,
+ filterText,
+ insertText,
+ insertTextFormat,
+ textEdit,
+ additionalTextEdits,
+ commitCharacters,
+ command,
+ data);
+ }
/// An optional array of additional text edits that are applied when selecting
/// this completion. Edits must not overlap (including the same insert
@@ -646,14 +1176,75 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('label') || !map['label'] is String) {
+ return false;
+ }
+ const validFieldNames = [
+ 'label',
+ 'kind',
+ 'detail',
+ 'documentation',
+ 'deprecated',
+ 'preselect',
+ 'sortText',
+ 'filterText',
+ 'insertText',
+ 'insertTextFormat',
+ 'textEdit',
+ 'additionalTextEdits',
+ 'commitCharacters',
+ 'command',
+ 'data'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// The kind of a completion entry.
class CompletionItemKind {
const CompletionItemKind._(this._value);
+ const CompletionItemKind.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ return true;
+ }
+ return false;
+ }
+
static const Text = const CompletionItemKind._(1);
static const Method = const CompletionItemKind._(2);
static const Function = const CompletionItemKind._(3);
@@ -694,7 +1285,22 @@
/// Represents a collection of completion items ([CompletionItem]) to be
/// presented in the editor.
class CompletionList {
- CompletionList(this.isIncomplete, this.items);
+ CompletionList(this.isIncomplete, this.items) {
+ if (isIncomplete == null) {
+ throw 'isIncomplete is required but was not provided';
+ }
+ if (items == null) {
+ throw 'items is required but was not provided';
+ }
+ }
+ factory CompletionList.fromJson(Map<String, dynamic> json) {
+ final isIncomplete = json['isIncomplete'];
+ final items = json['items']
+ ?.map((item) => new CompletionItem.fromJson(item))
+ ?.cast<CompletionItem>()
+ ?.toList();
+ return new CompletionList(isIncomplete, items);
+ }
/// This list it not complete. Further typing should result in recomputing
/// this list.
@@ -710,11 +1316,37 @@
__result['items'] = items ?? (throw 'items is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('isIncomplete') || !map['isIncomplete'] is bool) {
+ return false;
+ }
+ if (!map.containsKey('items') ||
+ !(map['items'] is List &&
+ (map['items'].length == 0 ||
+ map['items'].every((item) => CompletionItem.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['isIncomplete', 'items'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Completion options.
class CompletionOptions {
CompletionOptions(this.resolveProvider, this.triggerCharacters);
+ factory CompletionOptions.fromJson(Map<String, dynamic> json) {
+ final resolveProvider = json['resolveProvider'];
+ final triggerCharacters = json['triggerCharacters']
+ ?.map((item) => item)
+ ?.cast<String>()
+ ?.toList();
+ return new CompletionOptions(resolveProvider, triggerCharacters);
+ }
/// The server provides support to resolve additional information for a
/// completion item.
@@ -733,14 +1365,37 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['resolveProvider', 'triggerCharacters'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class CompletionParams implements TextDocumentPositionParams {
- CompletionParams(this.context, this.textDocument, this.position);
+ CompletionParams(this.context, this.textDocument, this.position) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (position == null) {
+ throw 'position is required but was not provided';
+ }
+ }
+ factory CompletionParams.fromJson(Map<String, dynamic> json) {
+ final context = new CompletionContext.fromJson(json['context']);
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ final position = new Position.fromJson(json['position']);
+ return new CompletionParams(context, textDocument, position);
+ }
- /// The completion context. This is only available if the client specifies to
- /// send this using `ClientCapabilities.textDocument.completion.contextSupport
- /// === true`
+ /// The completion context. This is only available if the client specifies
+ /// to send this using
+ /// `ClientCapabilities.textDocument.completion.contextSupport === true`
final CompletionContext context;
/// The position inside the text document.
@@ -760,11 +1415,40 @@
position ?? (throw 'position is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('position') || !Position.canParse(map['position'])) {
+ return false;
+ }
+ const validFieldNames = ['context', 'textDocument', 'position'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class CompletionRegistrationOptions implements TextDocumentRegistrationOptions {
CompletionRegistrationOptions(
this.triggerCharacters, this.resolveProvider, this.documentSelector);
+ factory CompletionRegistrationOptions.fromJson(Map<String, dynamic> json) {
+ final triggerCharacters = json['triggerCharacters']
+ ?.map((item) => item)
+ ?.cast<String>()
+ ?.toList();
+ final resolveProvider = json['resolveProvider'];
+ final documentSelector = json['documentSelector']
+ ?.map((item) => new DocumentFilter.fromJson(item))
+ ?.cast<DocumentFilter>()
+ ?.toList();
+ return new CompletionRegistrationOptions(
+ triggerCharacters, resolveProvider, documentSelector);
+ }
/// A document selector to identify the scope of the registration. If set to
/// null the document selector provided on the client side will be used.
@@ -775,11 +1459,11 @@
final bool resolveProvider;
/// Most tools trigger completion request automatically without explicitly
- /// requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically they
- /// do so when the user starts to type an identifier. For example if the user
- /// types `c` in a JavaScript file code complete will automatically pop up
- /// present `console` besides others as a completion item. Characters that
- /// make up identifiers don't need to be listed here.
+ /// requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically
+ /// they do so when the user starts to type an identifier. For example if
+ /// the user types `c` in a JavaScript file code complete will automatically
+ /// pop up present `console` besides others as a completion item. Characters
+ /// that make up identifiers don't need to be listed here.
///
/// If code complete should automatically be trigger on characters not being
/// valid inside an identifier (for example `.` in JavaScript) list them in
@@ -797,14 +1481,45 @@
__result['documentSelector'] = documentSelector;
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('documentSelector') ||
+ !(map['documentSelector'] is List &&
+ (map['documentSelector'].length == 0 ||
+ map['documentSelector']
+ .every((item) => DocumentFilter.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = [
+ 'triggerCharacters',
+ 'resolveProvider',
+ 'documentSelector'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// How a completion was triggered
class CompletionTriggerKind {
const CompletionTriggerKind._(this._value);
+ const CompletionTriggerKind.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 1:
+ case 2:
+ case 3:
+ return true;
+ }
+ return false;
+ }
+
/// Completion was triggered by typing an identifier (24x7 code complete),
/// manual invocation (e.g Ctrl+Space) or via API.
static const Invoked = const CompletionTriggerKind._(1);
@@ -813,7 +1528,8 @@
/// `triggerCharacters` properties of the `CompletionRegistrationOptions`.
static const TriggerCharacter = const CompletionTriggerKind._(2);
- /// Completion was re-triggered as the current completion list is incomplete.
+ /// Completion was re-triggered as the current completion list is
+ /// incomplete.
static const TriggerForIncompleteCompletions =
const CompletionTriggerKind._(3);
@@ -830,6 +1546,11 @@
class ConfigurationItem {
ConfigurationItem(this.scopeUri, this.section);
+ factory ConfigurationItem.fromJson(Map<String, dynamic> json) {
+ final scopeUri = json['scopeUri'];
+ final section = json['section'];
+ return new ConfigurationItem(scopeUri, section);
+ }
/// The scope to get the configuration section for.
final String scopeUri;
@@ -847,10 +1568,30 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['scopeUri', 'section'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ConfigurationParams {
- ConfigurationParams(this.items);
+ ConfigurationParams(this.items) {
+ if (items == null) {
+ throw 'items is required but was not provided';
+ }
+ }
+ factory ConfigurationParams.fromJson(Map<String, dynamic> json) {
+ final items = json['items']
+ ?.map((item) => new ConfigurationItem.fromJson(item))
+ ?.cast<ConfigurationItem>()
+ ?.toList();
+ return new ConfigurationParams(items);
+ }
final List<ConfigurationItem> items;
@@ -859,11 +1600,36 @@
__result['items'] = items ?? (throw 'items is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('items') ||
+ !(map['items'] is List &&
+ (map['items'].length == 0 ||
+ map['items']
+ .every((item) => ConfigurationItem.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['items'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Create file operation
class CreateFile implements FileOperation {
- CreateFile(this.uri, this.options);
+ CreateFile(this.uri, this.options) {
+ if (uri == null) {
+ throw 'uri is required but was not provided';
+ }
+ }
+ factory CreateFile.fromJson(Map<String, dynamic> json) {
+ final uri = json['uri'];
+ final options = new CreateFileOptions.fromJson(json['options']);
+ return new CreateFile(uri, options);
+ }
/// Additional options
final CreateFileOptions options;
@@ -879,11 +1645,28 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('uri') || !map['uri'] is String) {
+ return false;
+ }
+ const validFieldNames = ['uri', 'options'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Options to create a file.
class CreateFileOptions {
CreateFileOptions(this.overwrite, this.ignoreIfExists);
+ factory CreateFileOptions.fromJson(Map<String, dynamic> json) {
+ final overwrite = json['overwrite'];
+ final ignoreIfExists = json['ignoreIfExists'];
+ return new CreateFileOptions(overwrite, ignoreIfExists);
+ }
/// Ignore if exists.
final bool ignoreIfExists;
@@ -901,11 +1684,29 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['overwrite', 'ignoreIfExists'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Delete file operation
class DeleteFile implements FileOperation {
- DeleteFile(this.uri, this.options);
+ DeleteFile(this.uri, this.options) {
+ if (uri == null) {
+ throw 'uri is required but was not provided';
+ }
+ }
+ factory DeleteFile.fromJson(Map<String, dynamic> json) {
+ final uri = json['uri'];
+ final options = new DeleteFileOptions.fromJson(json['options']);
+ return new DeleteFile(uri, options);
+ }
/// Delete options.
final DeleteFileOptions options;
@@ -921,11 +1722,28 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('uri') || !map['uri'] is String) {
+ return false;
+ }
+ const validFieldNames = ['uri', 'options'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Delete file options
class DeleteFileOptions {
DeleteFileOptions(this.recursive, this.ignoreIfNotExists);
+ factory DeleteFileOptions.fromJson(Map<String, dynamic> json) {
+ final recursive = json['recursive'];
+ final ignoreIfNotExists = json['ignoreIfNotExists'];
+ return new DeleteFileOptions(recursive, ignoreIfNotExists);
+ }
/// Ignore the operation if the file doesn't exist.
final bool ignoreIfNotExists;
@@ -943,11 +1761,44 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['recursive', 'ignoreIfNotExists'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class Diagnostic {
Diagnostic(this.range, this.severity, this.code, this.source, this.message,
- this.relatedInformation);
+ this.relatedInformation) {
+ if (range == null) {
+ throw 'range is required but was not provided';
+ }
+ if (message == null) {
+ throw 'message is required but was not provided';
+ }
+ }
+ factory Diagnostic.fromJson(Map<String, dynamic> json) {
+ final range = new Range.fromJson(json['range']);
+ final severity = new DiagnosticSeverity.fromJson(json['severity']);
+ final code = json['code'] is num
+ ? new Either2<num, String>.t1(json['code'])
+ : (json['code'] is String
+ ? new Either2<num, String>.t2(json['code'])
+ : (throw '''${json['code']} was not one of (number, string)'''));
+ final source = json['source'];
+ final message = json['message'];
+ final relatedInformation = json['relatedInformation']
+ ?.map((item) => new DiagnosticRelatedInformation.fromJson(item))
+ ?.cast<DiagnosticRelatedInformation>()
+ ?.toList();
+ return new Diagnostic(
+ range, severity, code, source, message, relatedInformation);
+ }
/// The diagnostic's code, which might appear in the user interface.
final Either2<num, String> code;
@@ -958,8 +1809,9 @@
/// The range at which the message applies.
final Range range;
- /// An array of related diagnostic information, e.g. when symbol-names within
- /// a scope collide all definitions can be marked via this property.
+ /// An array of related diagnostic information, e.g. when symbol-names
+ /// within a scope collide all definitions can be marked via this
+ /// property.
final List<DiagnosticRelatedInformation> relatedInformation;
/// The diagnostic's severity. Can be omitted. If omitted it is up to the
@@ -989,13 +1841,47 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('range') || !Range.canParse(map['range'])) {
+ return false;
+ }
+ if (!map.containsKey('message') || !map['message'] is String) {
+ return false;
+ }
+ const validFieldNames = [
+ 'range',
+ 'severity',
+ 'code',
+ 'source',
+ 'message',
+ 'relatedInformation'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// Represents a related message and source code location for a diagnostic. This
-/// should be used to point to code locations that cause or related to a
-/// diagnostics, e.g when duplicating a symbol in a scope.
+/// Represents a related message and source code location for a diagnostic.
+/// This should be used to point to code locations that cause or related to
+/// a diagnostics, e.g when duplicating a symbol in a scope.
class DiagnosticRelatedInformation {
- DiagnosticRelatedInformation(this.location, this.message);
+ DiagnosticRelatedInformation(this.location, this.message) {
+ if (location == null) {
+ throw 'location is required but was not provided';
+ }
+ if (message == null) {
+ throw 'message is required but was not provided';
+ }
+ }
+ factory DiagnosticRelatedInformation.fromJson(Map<String, dynamic> json) {
+ final location = new Location.fromJson(json['location']);
+ final message = json['message'];
+ return new DiagnosticRelatedInformation(location, message);
+ }
/// The location of this related diagnostic information.
final Location location;
@@ -1011,13 +1897,40 @@
message ?? (throw 'message is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('location') || !Location.canParse(map['location'])) {
+ return false;
+ }
+ if (!map.containsKey('message') || !map['message'] is String) {
+ return false;
+ }
+ const validFieldNames = ['location', 'message'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DiagnosticSeverity {
const DiagnosticSeverity._(this._value);
+ const DiagnosticSeverity.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return true;
+ }
+ return false;
+ }
+
/// Reports an error.
static const Error = const DiagnosticSeverity._(1);
@@ -1042,7 +1955,15 @@
}
class DidChangeConfigurationParams {
- DidChangeConfigurationParams(this.settings);
+ DidChangeConfigurationParams(this.settings) {
+ if (settings == null) {
+ throw 'settings is required but was not provided';
+ }
+ }
+ factory DidChangeConfigurationParams.fromJson(Map<String, dynamic> json) {
+ final settings = json['settings'];
+ return new DidChangeConfigurationParams(settings);
+ }
/// The actual changed settings
final dynamic settings;
@@ -1053,18 +1974,47 @@
settings ?? (throw 'settings is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('settings') || !true) {
+ return false;
+ }
+ const validFieldNames = ['settings'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DidChangeTextDocumentParams {
- DidChangeTextDocumentParams(this.textDocument, this.contentChanges);
+ DidChangeTextDocumentParams(this.textDocument, this.contentChanges) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (contentChanges == null) {
+ throw 'contentChanges is required but was not provided';
+ }
+ }
+ factory DidChangeTextDocumentParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new VersionedTextDocumentIdentifier.fromJson(json['textDocument']);
+ final contentChanges = json['contentChanges']
+ ?.map((item) => new TextDocumentContentChangeEvent.fromJson(item))
+ ?.cast<TextDocumentContentChangeEvent>()
+ ?.toList();
+ return new DidChangeTextDocumentParams(textDocument, contentChanges);
+ }
- /// The actual content changes. The content changes describe single state
- /// changes to the document. So if there are two content changes c1 and c2 for
- /// a document in state S then c1 move the document to S' and c2 to S''.
+ /// The actual content changes. The content changes describe single
+ /// state changes to the document. So if there are two content changes
+ /// c1 and c2 for a document in state S then c1 move the document to S'
+ /// and c2 to S''.
final List<TextDocumentContentChangeEvent> contentChanges;
- /// The document that did change. The version number points to the version
- /// after all provided content changes have been applied.
+ /// The document that did change. The version number points to the
+ /// version after all provided content changes have been applied.
final VersionedTextDocumentIdentifier textDocument;
Map<String, dynamic> toJson() {
@@ -1075,10 +2025,41 @@
contentChanges ?? (throw 'contentChanges is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !VersionedTextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('contentChanges') ||
+ !(map['contentChanges'] is List &&
+ (map['contentChanges'].length == 0 ||
+ map['contentChanges'].every((item) =>
+ TextDocumentContentChangeEvent.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['textDocument', 'contentChanges'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DidChangeWatchedFilesParams {
- DidChangeWatchedFilesParams(this.changes);
+ DidChangeWatchedFilesParams(this.changes) {
+ if (changes == null) {
+ throw 'changes is required but was not provided';
+ }
+ }
+ factory DidChangeWatchedFilesParams.fromJson(Map<String, dynamic> json) {
+ final changes = json['changes']
+ ?.map((item) => new FileEvent.fromJson(item))
+ ?.cast<FileEvent>()
+ ?.toList();
+ return new DidChangeWatchedFilesParams(changes);
+ }
/// The actual file events.
final List<FileEvent> changes;
@@ -1089,12 +2070,39 @@
changes ?? (throw 'changes is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('changes') ||
+ !(map['changes'] is List &&
+ (map['changes'].length == 0 ||
+ map['changes'].every((item) => FileEvent.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['changes'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Describe options to be used when registering for text document change
/// events.
class DidChangeWatchedFilesRegistrationOptions {
- DidChangeWatchedFilesRegistrationOptions(this.watchers);
+ DidChangeWatchedFilesRegistrationOptions(this.watchers) {
+ if (watchers == null) {
+ throw 'watchers is required but was not provided';
+ }
+ }
+ factory DidChangeWatchedFilesRegistrationOptions.fromJson(
+ Map<String, dynamic> json) {
+ final watchers = json['watchers']
+ ?.map((item) => new FileSystemWatcher.fromJson(item))
+ ?.cast<FileSystemWatcher>()
+ ?.toList();
+ return new DidChangeWatchedFilesRegistrationOptions(watchers);
+ }
/// The watchers to register.
final List<FileSystemWatcher> watchers;
@@ -1105,10 +2113,34 @@
watchers ?? (throw 'watchers is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('watchers') ||
+ !(map['watchers'] is List &&
+ (map['watchers'].length == 0 ||
+ map['watchers']
+ .every((item) => FileSystemWatcher.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['watchers'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DidChangeWorkspaceFoldersParams {
- DidChangeWorkspaceFoldersParams(this.event);
+ DidChangeWorkspaceFoldersParams(this.event) {
+ if (event == null) {
+ throw 'event is required but was not provided';
+ }
+ }
+ factory DidChangeWorkspaceFoldersParams.fromJson(Map<String, dynamic> json) {
+ final event = new WorkspaceFoldersChangeEvent.fromJson(json['event']);
+ return new DidChangeWorkspaceFoldersParams(event);
+ }
/// The actual workspace folder change event.
final WorkspaceFoldersChangeEvent event;
@@ -1118,10 +2150,32 @@
__result['event'] = event ?? (throw 'event is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('event') ||
+ !WorkspaceFoldersChangeEvent.canParse(map['event'])) {
+ return false;
+ }
+ const validFieldNames = ['event'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DidCloseTextDocumentParams {
- DidCloseTextDocumentParams(this.textDocument);
+ DidCloseTextDocumentParams(this.textDocument) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ }
+ factory DidCloseTextDocumentParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ return new DidCloseTextDocumentParams(textDocument);
+ }
/// The document that was closed.
final TextDocumentIdentifier textDocument;
@@ -1132,10 +2186,31 @@
textDocument ?? (throw 'textDocument is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DidOpenTextDocumentParams {
- DidOpenTextDocumentParams(this.textDocument);
+ DidOpenTextDocumentParams(this.textDocument) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ }
+ factory DidOpenTextDocumentParams.fromJson(Map<String, dynamic> json) {
+ final textDocument = new TextDocumentItem.fromJson(json['textDocument']);
+ return new DidOpenTextDocumentParams(textDocument);
+ }
/// The document that was opened.
final TextDocumentItem textDocument;
@@ -1146,13 +2221,36 @@
textDocument ?? (throw 'textDocument is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentItem.canParse(map['textDocument'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DidSaveTextDocumentParams {
- DidSaveTextDocumentParams(this.textDocument, this.text);
+ DidSaveTextDocumentParams(this.textDocument, this.text) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ }
+ factory DidSaveTextDocumentParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ final text = json['text'];
+ return new DidSaveTextDocumentParams(textDocument, text);
+ }
- /// Optional the content when saved. Depends on the includeText value when the
- /// save notification was requested.
+ /// Optional the content when saved. Depends on the includeText value
+ /// when the save notification was requested.
final String text;
/// The document that was saved.
@@ -1167,10 +2265,29 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument', 'text'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DocumentFilter {
DocumentFilter(this.language, this.scheme, this.pattern);
+ factory DocumentFilter.fromJson(Map<String, dynamic> json) {
+ final language = json['language'];
+ final scheme = json['scheme'];
+ final pattern = json['pattern'];
+ return new DocumentFilter(language, scheme, pattern);
+ }
/// A language id, like `typescript`.
final String language;
@@ -1194,10 +2311,32 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['language', 'scheme', 'pattern'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DocumentFormattingParams {
- DocumentFormattingParams(this.textDocument, this.options);
+ DocumentFormattingParams(this.textDocument, this.options) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (options == null) {
+ throw 'options is required but was not provided';
+ }
+ }
+ factory DocumentFormattingParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ final options = new FormattingOptions.fromJson(json['options']);
+ return new DocumentFormattingParams(textDocument, options);
+ }
/// The format options.
final FormattingOptions options;
@@ -1213,13 +2352,39 @@
options ?? (throw 'options is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('options') ||
+ !FormattingOptions.canParse(map['options'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument', 'options'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// A document highlight is a range inside a text document which deserves
-/// special attention. Usually a document highlight is visualized by changing
-/// the background color of its range.
+/// special attention. Usually a document highlight is visualized by
+/// changing the background color of its range.
class DocumentHighlight {
- DocumentHighlight(this.range, this.kind);
+ DocumentHighlight(this.range, this.kind) {
+ if (range == null) {
+ throw 'range is required but was not provided';
+ }
+ }
+ factory DocumentHighlight.fromJson(Map<String, dynamic> json) {
+ final range = new Range.fromJson(json['range']);
+ final kind = new DocumentHighlightKind.fromJson(json['kind']);
+ return new DocumentHighlight(range, kind);
+ }
/// The highlight kind, default is DocumentHighlightKind.Text.
final DocumentHighlightKind kind;
@@ -1235,14 +2400,37 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('range') || !Range.canParse(map['range'])) {
+ return false;
+ }
+ const validFieldNames = ['range', 'kind'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// A document highlight kind.
class DocumentHighlightKind {
const DocumentHighlightKind._(this._value);
+ const DocumentHighlightKind.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 1:
+ case 2:
+ case 3:
+ return true;
+ }
+ return false;
+ }
+
/// A textual occurrence.
static const Text = const DocumentHighlightKind._(1);
@@ -1263,10 +2451,21 @@
bool operator ==(o) => o is DocumentHighlightKind && o._value == _value;
}
-/// A document link is a range in a text document that links to an internal or
-/// external resource, like another text document or a web site.
+/// A document link is a range in a text document that links to an
+/// internal or external resource, like another text document or a web
+/// site.
class DocumentLink {
- DocumentLink(this.range, this.target, this.data);
+ DocumentLink(this.range, this.target, this.data) {
+ if (range == null) {
+ throw 'range is required but was not provided';
+ }
+ }
+ factory DocumentLink.fromJson(Map<String, dynamic> json) {
+ final range = new Range.fromJson(json['range']);
+ final target = json['target'];
+ final data = json['data'];
+ return new DocumentLink(range, target, data);
+ }
/// A data entry field that is preserved on a document link between a
/// DocumentLinkRequest and a DocumentLinkResolveRequest.
@@ -1275,7 +2474,8 @@
/// The range this link applies to.
final Range range;
- /// The uri this link points to. If missing a resolve request is sent later.
+ /// The uri this link points to. If missing a resolve request is sent
+ /// later.
final String target;
Map<String, dynamic> toJson() {
@@ -1289,11 +2489,27 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('range') || !Range.canParse(map['range'])) {
+ return false;
+ }
+ const validFieldNames = ['range', 'target', 'data'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Document link options.
class DocumentLinkOptions {
DocumentLinkOptions(this.resolveProvider);
+ factory DocumentLinkOptions.fromJson(Map<String, dynamic> json) {
+ final resolveProvider = json['resolveProvider'];
+ return new DocumentLinkOptions(resolveProvider);
+ }
/// Document links have a resolve provider as well.
final bool resolveProvider;
@@ -1305,10 +2521,28 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['resolveProvider'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DocumentLinkParams {
- DocumentLinkParams(this.textDocument);
+ DocumentLinkParams(this.textDocument) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ }
+ factory DocumentLinkParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ return new DocumentLinkParams(textDocument);
+ }
/// The document to provide document links for.
final TextDocumentIdentifier textDocument;
@@ -1319,14 +2553,37 @@
textDocument ?? (throw 'textDocument is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DocumentLinkRegistrationOptions
implements TextDocumentRegistrationOptions {
DocumentLinkRegistrationOptions(this.resolveProvider, this.documentSelector);
+ factory DocumentLinkRegistrationOptions.fromJson(Map<String, dynamic> json) {
+ final resolveProvider = json['resolveProvider'];
+ final documentSelector = json['documentSelector']
+ ?.map((item) => new DocumentFilter.fromJson(item))
+ ?.cast<DocumentFilter>()
+ ?.toList();
+ return new DocumentLinkRegistrationOptions(
+ resolveProvider, documentSelector);
+ }
- /// A document selector to identify the scope of the registration. If set to
- /// null the document selector provided on the client side will be used.
+ /// A document selector to identify the scope of the registration. If
+ /// set to null the document selector provided on the client side will
+ /// be used.
final List<DocumentFilter> documentSelector;
/// Document links have a resolve provider as well.
@@ -1340,12 +2597,41 @@
__result['documentSelector'] = documentSelector;
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('documentSelector') ||
+ !(map['documentSelector'] is List &&
+ (map['documentSelector'].length == 0 ||
+ map['documentSelector']
+ .every((item) => DocumentFilter.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['resolveProvider', 'documentSelector'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Format document on type options.
class DocumentOnTypeFormattingOptions {
DocumentOnTypeFormattingOptions(
- this.firstTriggerCharacter, this.moreTriggerCharacter);
+ this.firstTriggerCharacter, this.moreTriggerCharacter) {
+ if (firstTriggerCharacter == null) {
+ throw 'firstTriggerCharacter is required but was not provided';
+ }
+ }
+ factory DocumentOnTypeFormattingOptions.fromJson(Map<String, dynamic> json) {
+ final firstTriggerCharacter = json['firstTriggerCharacter'];
+ final moreTriggerCharacter = json['moreTriggerCharacter']
+ ?.map((item) => item)
+ ?.cast<String>()
+ ?.toList();
+ return new DocumentOnTypeFormattingOptions(
+ firstTriggerCharacter, moreTriggerCharacter);
+ }
/// A character on which formatting should be triggered, like `}`.
final String firstTriggerCharacter;
@@ -1362,11 +2648,46 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('firstTriggerCharacter') ||
+ !map['firstTriggerCharacter'] is String) {
+ return false;
+ }
+ const validFieldNames = ['firstTriggerCharacter', 'moreTriggerCharacter'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DocumentOnTypeFormattingParams {
DocumentOnTypeFormattingParams(
- this.textDocument, this.position, this.ch, this.options);
+ this.textDocument, this.position, this.ch, this.options) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (position == null) {
+ throw 'position is required but was not provided';
+ }
+ if (ch == null) {
+ throw 'ch is required but was not provided';
+ }
+ if (options == null) {
+ throw 'options is required but was not provided';
+ }
+ }
+ factory DocumentOnTypeFormattingParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ final position = new Position.fromJson(json['position']);
+ final ch = json['ch'];
+ final options = new FormattingOptions.fromJson(json['options']);
+ return new DocumentOnTypeFormattingParams(
+ textDocument, position, ch, options);
+ }
/// The character that has been typed.
final String ch;
@@ -1391,15 +2712,57 @@
options ?? (throw 'options is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('position') || !Position.canParse(map['position'])) {
+ return false;
+ }
+ if (!map.containsKey('ch') || !map['ch'] is String) {
+ return false;
+ }
+ if (!map.containsKey('options') ||
+ !FormattingOptions.canParse(map['options'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument', 'position', 'ch', 'options'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DocumentOnTypeFormattingRegistrationOptions
implements TextDocumentRegistrationOptions {
DocumentOnTypeFormattingRegistrationOptions(this.firstTriggerCharacter,
- this.moreTriggerCharacter, this.documentSelector);
+ this.moreTriggerCharacter, this.documentSelector) {
+ if (firstTriggerCharacter == null) {
+ throw 'firstTriggerCharacter is required but was not provided';
+ }
+ }
+ factory DocumentOnTypeFormattingRegistrationOptions.fromJson(
+ Map<String, dynamic> json) {
+ final firstTriggerCharacter = json['firstTriggerCharacter'];
+ final moreTriggerCharacter = json['moreTriggerCharacter']
+ ?.map((item) => item)
+ ?.cast<String>()
+ ?.toList();
+ final documentSelector = json['documentSelector']
+ ?.map((item) => new DocumentFilter.fromJson(item))
+ ?.cast<DocumentFilter>()
+ ?.toList();
+ return new DocumentOnTypeFormattingRegistrationOptions(
+ firstTriggerCharacter, moreTriggerCharacter, documentSelector);
+ }
- /// A document selector to identify the scope of the registration. If set to
- /// null the document selector provided on the client side will be used.
+ /// A document selector to identify the scope of the registration. If
+ /// set to null the document selector provided on the client side will
+ /// be used.
final List<DocumentFilter> documentSelector;
/// A character on which formatting should be triggered, like `}`.
@@ -1418,10 +2781,51 @@
__result['documentSelector'] = documentSelector;
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('firstTriggerCharacter') ||
+ !map['firstTriggerCharacter'] is String) {
+ return false;
+ }
+ if (!map.containsKey('documentSelector') ||
+ !(map['documentSelector'] is List &&
+ (map['documentSelector'].length == 0 ||
+ map['documentSelector']
+ .every((item) => DocumentFilter.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = [
+ 'firstTriggerCharacter',
+ 'moreTriggerCharacter',
+ 'documentSelector'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DocumentRangeFormattingParams {
- DocumentRangeFormattingParams(this.textDocument, this.range, this.options);
+ DocumentRangeFormattingParams(this.textDocument, this.range, this.options) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (range == null) {
+ throw 'range is required but was not provided';
+ }
+ if (options == null) {
+ throw 'options is required but was not provided';
+ }
+ }
+ factory DocumentRangeFormattingParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ final range = new Range.fromJson(json['range']);
+ final options = new FormattingOptions.fromJson(json['options']);
+ return new DocumentRangeFormattingParams(textDocument, range, options);
+ }
/// The format options
final FormattingOptions options;
@@ -1441,15 +2845,63 @@
options ?? (throw 'options is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('range') || !Range.canParse(map['range'])) {
+ return false;
+ }
+ if (!map.containsKey('options') ||
+ !FormattingOptions.canParse(map['options'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument', 'range', 'options'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// Represents programming constructs like variables, classes, interfaces etc.
-/// that appear in a document. Document symbols can be hierarchical and they
-/// have two ranges: one that encloses its definition and one that points to its
-/// most interesting range, e.g. the range of an identifier.
+/// Represents programming constructs like variables, classes,
+/// interfaces etc. that appear in a document. Document symbols can be
+/// hierarchical and they have two ranges: one that encloses its
+/// definition and one that points to its most interesting range, e.g.
+/// the range of an identifier.
class DocumentSymbol {
DocumentSymbol(this.name, this.detail, this.kind, this.deprecated, this.range,
- this.selectionRange, this.children);
+ this.selectionRange, this.children) {
+ if (name == null) {
+ throw 'name is required but was not provided';
+ }
+ if (kind == null) {
+ throw 'kind is required but was not provided';
+ }
+ if (range == null) {
+ throw 'range is required but was not provided';
+ }
+ if (selectionRange == null) {
+ throw 'selectionRange is required but was not provided';
+ }
+ }
+ factory DocumentSymbol.fromJson(Map<String, dynamic> json) {
+ final name = json['name'];
+ final detail = json['detail'];
+ final kind = new SymbolKind.fromJson(json['kind']);
+ final deprecated = json['deprecated'];
+ final range = new Range.fromJson(json['range']);
+ final selectionRange = new Range.fromJson(json['selectionRange']);
+ final children = json['children']
+ ?.map((item) => new DocumentSymbol.fromJson(item))
+ ?.cast<DocumentSymbol>()
+ ?.toList();
+ return new DocumentSymbol(
+ name, detail, kind, deprecated, range, selectionRange, children);
+ }
/// Children of this symbol, e.g. properties of a class.
final List<DocumentSymbol> children;
@@ -1466,14 +2918,15 @@
/// The name of this symbol.
final String name;
- /// The range enclosing this symbol not including leading/trailing whitespace
- /// but everything else like comments. This information is typically used to
- /// determine if the clients cursor is inside the symbol to reveal in the
- /// symbol in the UI.
+ /// The range enclosing this symbol not including leading/trailing
+ /// whitespace but everything else like comments. This information is
+ /// typically used to determine if the clients cursor is inside the
+ /// symbol to reveal in the symbol in the UI.
final Range range;
- /// The range that should be selected and revealed when this symbol is being
- /// picked, e.g the name of a function. Must be contained by the `range`.
+ /// The range that should be selected and revealed when this symbol is
+ /// being picked, e.g the name of a function. Must be contained by the
+ /// `range`.
final Range selectionRange;
Map<String, dynamic> toJson() {
@@ -1494,10 +2947,49 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('name') || !map['name'] is String) {
+ return false;
+ }
+ if (!map.containsKey('kind') || !SymbolKind.canParse(map['kind'])) {
+ return false;
+ }
+ if (!map.containsKey('range') || !Range.canParse(map['range'])) {
+ return false;
+ }
+ if (!map.containsKey('selectionRange') ||
+ !Range.canParse(map['selectionRange'])) {
+ return false;
+ }
+ const validFieldNames = [
+ 'name',
+ 'detail',
+ 'kind',
+ 'deprecated',
+ 'range',
+ 'selectionRange',
+ 'children'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class DocumentSymbolParams {
- DocumentSymbolParams(this.textDocument);
+ DocumentSymbolParams(this.textDocument) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ }
+ factory DocumentSymbolParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ return new DocumentSymbolParams(textDocument);
+ }
/// The text document.
final TextDocumentIdentifier textDocument;
@@ -1508,6 +3000,19 @@
textDocument ?? (throw 'textDocument is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
abstract class ErrorCodes {
@@ -1525,7 +3030,16 @@
/// Execute command options.
class ExecuteCommandOptions {
- ExecuteCommandOptions(this.commands);
+ ExecuteCommandOptions(this.commands) {
+ if (commands == null) {
+ throw 'commands is required but was not provided';
+ }
+ }
+ factory ExecuteCommandOptions.fromJson(Map<String, dynamic> json) {
+ final commands =
+ json['commands']?.map((item) => item)?.cast<String>()?.toList();
+ return new ExecuteCommandOptions(commands);
+ }
/// The commands to be executed on the server
final List<String> commands;
@@ -1536,10 +3050,35 @@
commands ?? (throw 'commands is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('commands') ||
+ !(map['commands'] is List &&
+ (map['commands'].length == 0 ||
+ map['commands'].every((item) => item is String)))) {
+ return false;
+ }
+ const validFieldNames = ['commands'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ExecuteCommandParams {
- ExecuteCommandParams(this.command, this.arguments);
+ ExecuteCommandParams(this.command, this.arguments) {
+ if (command == null) {
+ throw 'command is required but was not provided';
+ }
+ }
+ factory ExecuteCommandParams.fromJson(Map<String, dynamic> json) {
+ final command = json['command'];
+ final arguments =
+ json['arguments']?.map((item) => item)?.cast<dynamic>()?.toList();
+ return new ExecuteCommandParams(command, arguments);
+ }
/// Arguments that the command should be invoked with.
final List<dynamic> arguments;
@@ -1556,11 +3095,33 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('command') || !map['command'] is String) {
+ return false;
+ }
+ const validFieldNames = ['command', 'arguments'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Execute command registration options.
class ExecuteCommandRegistrationOptions {
- ExecuteCommandRegistrationOptions(this.commands);
+ ExecuteCommandRegistrationOptions(this.commands) {
+ if (commands == null) {
+ throw 'commands is required but was not provided';
+ }
+ }
+ factory ExecuteCommandRegistrationOptions.fromJson(
+ Map<String, dynamic> json) {
+ final commands =
+ json['commands']?.map((item) => item)?.cast<String>()?.toList();
+ return new ExecuteCommandRegistrationOptions(commands);
+ }
/// The commands to be executed on the server
final List<String> commands;
@@ -1571,30 +3132,59 @@
commands ?? (throw 'commands is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('commands') ||
+ !(map['commands'] is List &&
+ (map['commands'].length == 0 ||
+ map['commands'].every((item) => item is String)))) {
+ return false;
+ }
+ const validFieldNames = ['commands'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class FailureHandlingKind {
const FailureHandlingKind._(this._value);
+ const FailureHandlingKind.fromJson(this._value);
final Object _value;
- /// Applying the workspace change is simply aborted if one of the changes
- /// provided fails. All operations executed before the failing operation stay
- /// executed.
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 'abort':
+ case 'transactional':
+ case 'textOnlyTransactional':
+ case 'undo':
+ return true;
+ }
+ return false;
+ }
+
+ /// Applying the workspace change is simply aborted if one of the
+ /// changes provided fails. All operations executed before the
+ /// failing operation stay executed.
static const Abort = const FailureHandlingKind._('abort');
- /// All operations are executed transactional. That means they either all
- /// succeed or no changes at all are applied to the workspace.
+ /// All operations are executed transactional. That means they
+ /// either all succeed or no changes at all are applied to the
+ /// workspace.
static const Transactional = const FailureHandlingKind._('transactional');
- /// If the workspace edit contains only textual file changes they are executed
- /// transactional. If resource changes (create, rename or delete file) are
- /// part of the change the failure handling startegy is abort.
+ /// If the workspace edit contains only textual file changes they
+ /// are executed transactional. If resource changes (create, rename
+ /// or delete file) are part of the change the failure handling
+ /// startegy is abort.
static const TextOnlyTransactional =
const FailureHandlingKind._('textOnlyTransactional');
- /// The client tries to undo the operations already executed. But there is no
- /// guaruntee that this is succeeding.
+ /// The client tries to undo the operations already executed. But
+ /// there is no guaruntee that this is succeeding.
static const Undo = const FailureHandlingKind._('undo');
Object toJson() => _value;
@@ -1611,9 +3201,20 @@
/// The file event type.
class FileChangeType {
const FileChangeType._(this._value);
+ const FileChangeType.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 1:
+ case 2:
+ case 3:
+ return true;
+ }
+ return false;
+ }
+
/// The file got created.
static const Created = const FileChangeType._(1);
@@ -1636,7 +3237,19 @@
/// An event describing a file change.
class FileEvent {
- FileEvent(this.uri, this.type);
+ FileEvent(this.uri, this.type) {
+ if (uri == null) {
+ throw 'uri is required but was not provided';
+ }
+ if (type == null) {
+ throw 'type is required but was not provided';
+ }
+ }
+ factory FileEvent.fromJson(Map<String, dynamic> json) {
+ final uri = json['uri'];
+ final type = json['type'];
+ return new FileEvent(uri, type);
+ }
/// The change type.
final num type;
@@ -1650,16 +3263,41 @@
__result['type'] = type ?? (throw 'type is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('uri') || !map['uri'] is String) {
+ return false;
+ }
+ if (!map.containsKey('type') || !map['type'] is num) {
+ return false;
+ }
+ const validFieldNames = ['uri', 'type'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class FileSystemWatcher {
- FileSystemWatcher(this.globPattern, this.kind);
+ FileSystemWatcher(this.globPattern, this.kind) {
+ if (globPattern == null) {
+ throw 'globPattern is required but was not provided';
+ }
+ }
+ factory FileSystemWatcher.fromJson(Map<String, dynamic> json) {
+ final globPattern = json['globPattern'];
+ final kind = new WatchKind.fromJson(json['kind']);
+ return new FileSystemWatcher(globPattern, kind);
+ }
/// The glob pattern to watch
final String globPattern;
- /// The kind of events of interest. If omitted it defaults to WatchKind.Create
- /// | WatchKind.Change | WatchKind.Delete which is 7.
+ /// The kind of events of interest. If omitted it defaults to
+ /// WatchKind.Create | WatchKind.Change | WatchKind.Delete which
+ /// is 7.
final WatchKind kind;
Map<String, dynamic> toJson() {
@@ -1671,28 +3309,57 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('globPattern') || !map['globPattern'] is String) {
+ return false;
+ }
+ const validFieldNames = ['globPattern', 'kind'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Represents a folding range.
class FoldingRange {
FoldingRange(this.startLine, this.startCharacter, this.endLine,
- this.endCharacter, this.kind);
+ this.endCharacter, this.kind) {
+ if (startLine == null) {
+ throw 'startLine is required but was not provided';
+ }
+ if (endLine == null) {
+ throw 'endLine is required but was not provided';
+ }
+ }
+ factory FoldingRange.fromJson(Map<String, dynamic> json) {
+ final startLine = json['startLine'];
+ final startCharacter = json['startCharacter'];
+ final endLine = json['endLine'];
+ final endCharacter = json['endCharacter'];
+ final kind = new FoldingRangeKind.fromJson(json['kind']);
+ return new FoldingRange(
+ startLine, startCharacter, endLine, endCharacter, kind);
+ }
- /// The zero-based character offset before the folded range ends. If not
- /// defined, defaults to the length of the end line.
+ /// The zero-based character offset before the folded range ends.
+ /// If not defined, defaults to the length of the end line.
final num endCharacter;
/// The zero-based line number where the folded range ends.
final num endLine;
- /// Describes the kind of the folding range such as `comment' or 'region'. The
- /// kind is used to categorize folding ranges and used by commands like 'Fold
- /// all comments'. See [FoldingRangeKind] for an enumeration of standardized
- /// kinds.
+ /// Describes the kind of the folding range such as `comment' or
+ /// 'region'. The kind is used to categorize folding ranges and
+ /// used by commands like 'Fold all comments'. See
+ /// [FoldingRangeKind] for an enumeration of standardized kinds.
final FoldingRangeKind kind;
- /// The zero-based character offset from where the folded range starts. If not
- /// defined, defaults to the length of the start line.
+ /// The zero-based character offset from where the folded range
+ /// starts. If not defined, defaults to the length of the start
+ /// line.
final num startCharacter;
/// The zero-based line number from where the folded range starts.
@@ -1715,14 +3382,46 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('startLine') || !map['startLine'] is num) {
+ return false;
+ }
+ if (!map.containsKey('endLine') || !map['endLine'] is num) {
+ return false;
+ }
+ const validFieldNames = [
+ 'startLine',
+ 'startCharacter',
+ 'endLine',
+ 'endCharacter',
+ 'kind'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Enum of known range kinds
class FoldingRangeKind {
const FoldingRangeKind._(this._value);
+ const FoldingRangeKind.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 'comment':
+ case 'imports':
+ case 'region':
+ return true;
+ }
+ return false;
+ }
+
/// Folding range for a comment
static const Comment = const FoldingRangeKind._('comment');
@@ -1744,7 +3443,16 @@
}
class FoldingRangeParams {
- FoldingRangeParams(this.textDocument);
+ FoldingRangeParams(this.textDocument) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ }
+ factory FoldingRangeParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ return new FoldingRangeParams(textDocument);
+ }
/// The text document.
final TextDocumentIdentifier textDocument;
@@ -1755,6 +3463,19 @@
textDocument ?? (throw 'textDocument is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Folding range provider options.
@@ -1763,11 +3484,32 @@
Map<String, dynamic> __result = {};
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = [''];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Value-object describing what options formatting should use.
class FormattingOptions {
- FormattingOptions(this.tabSize, this.insertSpaces);
+ FormattingOptions(this.tabSize, this.insertSpaces) {
+ if (tabSize == null) {
+ throw 'tabSize is required but was not provided';
+ }
+ if (insertSpaces == null) {
+ throw 'insertSpaces is required but was not provided';
+ }
+ }
+ factory FormattingOptions.fromJson(Map<String, dynamic> json) {
+ final tabSize = json['tabSize'];
+ final insertSpaces = json['insertSpaces'];
+ return new FormattingOptions(tabSize, insertSpaces);
+ }
/// Prefer spaces over tabs.
final bool insertSpaces;
@@ -1783,17 +3525,58 @@
insertSpaces ?? (throw 'insertSpaces is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('tabSize') || !map['tabSize'] is num) {
+ return false;
+ }
+ if (!map.containsKey('insertSpaces') || !map['insertSpaces'] is bool) {
+ return false;
+ }
+ const validFieldNames = ['tabSize', 'insertSpaces'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// The result of a hover request.
class Hover {
- Hover(this.contents, this.range);
+ Hover(this.contents, this.range) {
+ if (contents == null) {
+ throw 'contents is required but was not provided';
+ }
+ }
+ factory Hover.fromJson(Map<String, dynamic> json) {
+ final contents = MarkedString.canParse(json['contents'])
+ ? new Either3<MarkedString, List<MarkedString>, MarkupContent>.t1(
+ new MarkedString.fromJson(json['contents']))
+ : ((json['contents'] is List &&
+ (json['contents'].length == 0 ||
+ json['contents']
+ .every((item) => MarkedString.canParse(item))))
+ ? new Either3<MarkedString, List<MarkedString>, MarkupContent>.t2(
+ json['contents']
+ ?.map((item) => new MarkedString.fromJson(item))
+ ?.cast<MarkedString>()
+ ?.toList())
+ : (MarkupContent.canParse(json['contents'])
+ ? new Either3<MarkedString, List<MarkedString>,
+ MarkupContent>.t3(
+ new MarkupContent.fromJson(json['contents']))
+ : (throw '''${json['contents']} was not one of (MarkedString, MarkedString[], MarkupContent)''')));
+ final range = new Range.fromJson(json['range']);
+ return new Hover(contents, range);
+ }
/// The hover's content
final Either3<MarkedString, List<MarkedString>, MarkupContent> contents;
- /// An optional range is a range inside a text document that is used to
- /// visualize a hover, e.g. by changing the background color.
+ /// An optional range is a range inside a text document that is
+ /// used to visualize a hover, e.g. by changing the background
+ /// color.
final Range range;
Map<String, dynamic> toJson() {
@@ -1805,11 +3588,46 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('contents') ||
+ !(MarkedString.canParse(map['contents']) ||
+ (map['contents'] is List &&
+ (map['contents'].length == 0 ||
+ map['contents']
+ .every((item) => MarkedString.canParse(item)))) ||
+ MarkupContent.canParse(map['contents']))) {
+ return false;
+ }
+ const validFieldNames = ['contents', 'range'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class InitializeParams {
InitializeParams(this.processId, this.rootPath, this.rootUri,
- this.initializationOptions, this.capabilities, this.workspaceFolders);
+ this.initializationOptions, this.capabilities, this.workspaceFolders) {
+ if (capabilities == null) {
+ throw 'capabilities is required but was not provided';
+ }
+ }
+ factory InitializeParams.fromJson(Map<String, dynamic> json) {
+ final processId = json['processId'];
+ final rootPath = json['rootPath'];
+ final rootUri = json['rootUri'];
+ final initializationOptions = json['initializationOptions'];
+ final capabilities = new ClientCapabilities.fromJson(json['capabilities']);
+ final workspaceFolders = json['workspaceFolders']
+ ?.map((item) => new WorkspaceFolder.fromJson(item))
+ ?.cast<WorkspaceFolder>()
+ ?.toList();
+ return new InitializeParams(processId, rootPath, rootUri,
+ initializationOptions, capabilities, workspaceFolders);
+ }
/// The capabilities provided by the client (editor or tool)
final ClientCapabilities capabilities;
@@ -1817,10 +3635,10 @@
/// User provided initialization options.
final dynamic initializationOptions;
- /// The process Id of the parent process that started the server. Is null if
- /// the process has not been started by another process. If the parent process
- /// is not alive then the server should exit (see exit notification) its
- /// process.
+ /// The process Id of the parent process that started the
+ /// server. Is null if the process has not been started by
+ /// another process. If the parent process is not alive then the
+ /// server should exit (see exit notification) its process.
final num processId;
/// The rootPath of the workspace. Is null if no folder is open.
@@ -1828,14 +3646,14 @@
@core.deprecated
final String rootPath;
- /// The rootUri of the workspace. Is null if no folder is open. If both
- /// `rootPath` and `rootUri` are set `rootUri` wins.
+ /// The rootUri of the workspace. Is null if no folder is open.
+ /// If both `rootPath` and `rootUri` are set `rootUri` wins.
final String rootUri;
- /// The workspace folders configured in the client when the server starts.
- /// This property is only available if the client supports workspace folders.
- /// It can be `null` if the client supports workspace folders but none are
- /// configured.
+ /// The workspace folders configured in the client when the
+ /// server starts. This property is only available if the client
+ /// supports workspace folders. It can be `null` if the client
+ /// supports workspace folders but none are configured.
///
/// Since 3.6.0
final List<WorkspaceFolder> workspaceFolders;
@@ -1859,10 +3677,44 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('processId') || !map['processId'] is num) {
+ return false;
+ }
+ if (!map.containsKey('rootUri') || !map['rootUri'] is String) {
+ return false;
+ }
+ if (!map.containsKey('capabilities') ||
+ !ClientCapabilities.canParse(map['capabilities'])) {
+ return false;
+ }
+ const validFieldNames = [
+ 'processId',
+ 'rootPath',
+ 'rootUri',
+ 'initializationOptions',
+ 'capabilities',
+ 'workspaceFolders'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class InitializeResult {
- InitializeResult(this.capabilities);
+ InitializeResult(this.capabilities) {
+ if (capabilities == null) {
+ throw 'capabilities is required but was not provided';
+ }
+ }
+ factory InitializeResult.fromJson(Map<String, dynamic> json) {
+ final capabilities = new ServerCapabilities.fromJson(json['capabilities']);
+ return new InitializeResult(capabilities);
+ }
/// The capabilities the language server provides.
final ServerCapabilities capabilities;
@@ -1873,6 +3725,19 @@
capabilities ?? (throw 'capabilities is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('capabilities') ||
+ !ServerCapabilities.canParse(map['capabilities'])) {
+ return false;
+ }
+ const validFieldNames = ['capabilities'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class InitializedParams {
@@ -1880,24 +3745,45 @@
Map<String, dynamic> __result = {};
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = [''];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// Defines whether the insert text in a completion item should be interpreted
-/// as plain text or a snippet.
+/// Defines whether the insert text in a completion item should be
+/// interpreted as plain text or a snippet.
class InsertTextFormat {
const InsertTextFormat._(this._value);
+ const InsertTextFormat.fromJson(this._value);
final Object _value;
- /// The primary text to be inserted is treated as a plain string.
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 1:
+ case 2:
+ return true;
+ }
+ return false;
+ }
+
+ /// The primary text to be inserted is treated as a plain
+ /// string.
static const PlainText = const InsertTextFormat._(1);
/// The primary text to be inserted is treated as a snippet.
///
- /// A snippet can define tab stops and placeholders with `$1`, `$2` and
- /// `${3:foo}`. `$0` defines the final tab stop, it defaults to the end of the
- /// snippet. Placeholders with equal identifiers are linked, that is typing in
- /// one will update others too.
+ /// A snippet can define tab stops and placeholders with `$1`,
+ /// `$2` and `${3:foo}`. `$0` defines the final tab stop, it
+ /// defaults to the end of the snippet. Placeholders with
+ /// equal identifiers are linked, that is typing in one will
+ /// update others too.
static const Snippet = const InsertTextFormat._(2);
Object toJson() => _value;
@@ -1912,7 +3798,19 @@
}
class Location {
- Location(this.uri, this.range);
+ Location(this.uri, this.range) {
+ if (uri == null) {
+ throw 'uri is required but was not provided';
+ }
+ if (range == null) {
+ throw 'range is required but was not provided';
+ }
+ }
+ factory Location.fromJson(Map<String, dynamic> json) {
+ final uri = json['uri'];
+ final range = new Range.fromJson(json['range']);
+ return new Location(uri, range);
+ }
final Range range;
final String uri;
@@ -1923,10 +3821,37 @@
__result['range'] = range ?? (throw 'range is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('uri') || !map['uri'] is String) {
+ return false;
+ }
+ if (!map.containsKey('range') || !Range.canParse(map['range'])) {
+ return false;
+ }
+ const validFieldNames = ['uri', 'range'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class LogMessageParams {
- LogMessageParams(this.type, this.message);
+ LogMessageParams(this.type, this.message) {
+ if (type == null) {
+ throw 'type is required but was not provided';
+ }
+ if (message == null) {
+ throw 'message is required but was not provided';
+ }
+ }
+ factory LogMessageParams.fromJson(Map<String, dynamic> json) {
+ final type = new MessageType.fromJson(json['type']);
+ final message = json['message'];
+ return new LogMessageParams(type, message);
+ }
/// The actual message
final String message;
@@ -1941,10 +3866,37 @@
message ?? (throw 'message is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('type') || !MessageType.canParse(map['type'])) {
+ return false;
+ }
+ if (!map.containsKey('message') || !map['message'] is String) {
+ return false;
+ }
+ const validFieldNames = ['type', 'message'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class MarkedString {
- MarkedString(this.language, this.value);
+ MarkedString(this.language, this.value) {
+ if (language == null) {
+ throw 'language is required but was not provided';
+ }
+ if (value == null) {
+ throw 'value is required but was not provided';
+ }
+ }
+ factory MarkedString.fromJson(Map<String, dynamic> json) {
+ final language = json['language'];
+ final value = json['value'];
+ return new MarkedString(language, value);
+ }
final String language;
final String value;
@@ -1956,18 +3908,35 @@
__result['value'] = value ?? (throw 'value is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('language') || !map['language'] is String) {
+ return false;
+ }
+ if (!map.containsKey('value') || !map['value'] is String) {
+ return false;
+ }
+ const validFieldNames = ['language', 'value'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// A `MarkupContent` literal represents a string value which content is
-/// interpreted base on its kind flag. Currently the protocol supports
-/// `plaintext` and `markdown` as markup kinds.
+/// A `MarkupContent` literal represents a string value which
+/// content is interpreted base on its kind flag. Currently the
+/// protocol supports `plaintext` and `markdown` as markup
+/// kinds.
///
-/// If the kind is `markdown` then the value can contain fenced code blocks like
-/// in GitHub issues. See
+/// If the kind is `markdown` then the value can contain fenced
+/// code blocks like in GitHub issues. See
/// https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
///
-/// Here is an example how such a string can be constructed using JavaScript /
-/// TypeScript: ```ts let markdown: MarkdownContent = {
+/// Here is an example how such a string can be constructed
+/// using JavaScript / TypeScript: ```ts let markdown:
+/// MarkdownContent = {
///
/// kind: MarkupKind.Markdown,
/// value: [
@@ -1978,10 +3947,23 @@
/// '```'
/// ].join('\n') }; ```
///
-/// *Please Note* that clients might sanitize the return markdown. A client
-/// could decide to remove HTML from the markdown to avoid script execution.
+/// *Please Note* that clients might sanitize the return
+/// markdown. A client could decide to remove HTML from the
+/// markdown to avoid script execution.
class MarkupContent {
- MarkupContent(this.kind, this.value);
+ MarkupContent(this.kind, this.value) {
+ if (kind == null) {
+ throw 'kind is required but was not provided';
+ }
+ if (value == null) {
+ throw 'value is required but was not provided';
+ }
+ }
+ factory MarkupContent.fromJson(Map<String, dynamic> json) {
+ final kind = new MarkupKind.fromJson(json['kind']);
+ final value = json['value'];
+ return new MarkupContent(kind, value);
+ }
/// The type of the Markup
final MarkupKind kind;
@@ -1995,18 +3977,44 @@
__result['value'] = value ?? (throw 'value is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('kind') || !MarkupKind.canParse(map['kind'])) {
+ return false;
+ }
+ if (!map.containsKey('value') || !map['value'] is String) {
+ return false;
+ }
+ const validFieldNames = ['kind', 'value'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// Describes the content type that a client supports in various result literals
-/// like `Hover`, `ParameterInfo` or `CompletionItem`.
+/// Describes the content type that a client supports in various
+/// result literals like `Hover`, `ParameterInfo` or
+/// `CompletionItem`.
///
-/// Please note that `MarkupKinds` must not start with a `$`. This kinds are
-/// reserved for internal usage.
+/// Please note that `MarkupKinds` must not start with a `$`.
+/// This kinds are reserved for internal usage.
class MarkupKind {
const MarkupKind._(this._value);
+ const MarkupKind.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 'plaintext':
+ case 'markdown':
+ return true;
+ }
+ return false;
+ }
+
/// Plain text is supported as a content format
static const PlainText = const MarkupKind._('plaintext');
@@ -2025,7 +4033,15 @@
}
class Message {
- Message(this.jsonrpc);
+ Message(this.jsonrpc) {
+ if (jsonrpc == null) {
+ throw 'jsonrpc is required but was not provided';
+ }
+ }
+ factory Message.fromJson(Map<String, dynamic> json) {
+ final jsonrpc = json['jsonrpc'];
+ return new Message(jsonrpc);
+ }
final String jsonrpc;
@@ -2035,10 +4051,30 @@
jsonrpc ?? (throw 'jsonrpc is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('jsonrpc') || !map['jsonrpc'] is String) {
+ return false;
+ }
+ const validFieldNames = ['jsonrpc'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class MessageActionItem {
- MessageActionItem(this.title);
+ MessageActionItem(this.title) {
+ if (title == null) {
+ throw 'title is required but was not provided';
+ }
+ }
+ factory MessageActionItem.fromJson(Map<String, dynamic> json) {
+ final title = json['title'];
+ return new MessageActionItem(title);
+ }
/// A short title like 'Retry', 'Open Log' etc.
final String title;
@@ -2048,13 +4084,37 @@
__result['title'] = title ?? (throw 'title is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('title') || !map['title'] is String) {
+ return false;
+ }
+ const validFieldNames = ['title'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class MessageType {
const MessageType._(this._value);
+ const MessageType.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return true;
+ }
+ return false;
+ }
+
/// An error message.
static const Error = const MessageType._(1);
@@ -2079,7 +4139,19 @@
}
class NotificationMessage implements Message {
- NotificationMessage(this.method, this.jsonrpc);
+ NotificationMessage(this.method, this.jsonrpc) {
+ if (method == null) {
+ throw 'method is required but was not provided';
+ }
+ if (jsonrpc == null) {
+ throw 'jsonrpc is required but was not provided';
+ }
+ }
+ factory NotificationMessage.fromJson(Map<String, dynamic> json) {
+ final method = json['method'];
+ final jsonrpc = json['jsonrpc'];
+ return new NotificationMessage(method, jsonrpc);
+ }
final String jsonrpc;
@@ -2093,15 +4165,44 @@
jsonrpc ?? (throw 'jsonrpc is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('method') || !map['method'] is String) {
+ return false;
+ }
+ if (!map.containsKey('jsonrpc') || !map['jsonrpc'] is String) {
+ return false;
+ }
+ const validFieldNames = ['method', 'jsonrpc'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// Represents a parameter of a callable-signature. A parameter can have a label
-/// and a doc-comment.
+/// Represents a parameter of a callable-signature. A
+/// parameter can have a label and a doc-comment.
class ParameterInformation {
- ParameterInformation(this.label, this.documentation);
+ ParameterInformation(this.label, this.documentation) {
+ if (label == null) {
+ throw 'label is required but was not provided';
+ }
+ }
+ factory ParameterInformation.fromJson(Map<String, dynamic> json) {
+ final label = json['label'];
+ final documentation = json['documentation'] is String
+ ? new Either2<String, MarkupContent>.t1(json['documentation'])
+ : (MarkupContent.canParse(json['documentation'])
+ ? new Either2<String, MarkupContent>.t2(
+ new MarkupContent.fromJson(json['documentation']))
+ : (throw '''${json['documentation']} was not one of (string, MarkupContent)'''));
+ return new ParameterInformation(label, documentation);
+ }
- /// The human-readable doc-comment of this parameter. Will be shown in the UI
- /// but can be omitted.
+ /// The human-readable doc-comment of this parameter. Will
+ /// be shown in the UI but can be omitted.
final Either2<String, MarkupContent> documentation;
/// The label of this parameter. Will be shown in the UI.
@@ -2115,17 +4216,42 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('label') || !map['label'] is String) {
+ return false;
+ }
+ const validFieldNames = ['label', 'documentation'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class Position {
- Position(this.line, this.character);
+ Position(this.line, this.character) {
+ if (line == null) {
+ throw 'line is required but was not provided';
+ }
+ if (character == null) {
+ throw 'character is required but was not provided';
+ }
+ }
+ factory Position.fromJson(Map<String, dynamic> json) {
+ final line = json['line'];
+ final character = json['character'];
+ return new Position(line, character);
+ }
- /// Character offset on a line in a document (zero-based). Assuming that the
- /// line is represented as a string, the `character` value represents the gap
- /// between the `character` and `character + 1`.
+ /// Character offset on a line in a document (zero-based).
+ /// Assuming that the line is represented as a string, the
+ /// `character` value represents the gap between the
+ /// `character` and `character + 1`.
///
- /// If the character value is greater than the line length it defaults back to
- /// the line length.
+ /// If the character value is greater than the line length
+ /// it defaults back to the line length.
final num character;
/// Line position in a document (zero-based).
@@ -2138,10 +4264,40 @@
character ?? (throw 'character is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('line') || !map['line'] is num) {
+ return false;
+ }
+ if (!map.containsKey('character') || !map['character'] is num) {
+ return false;
+ }
+ const validFieldNames = ['line', 'character'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class PublishDiagnosticsParams {
- PublishDiagnosticsParams(this.uri, this.diagnostics);
+ PublishDiagnosticsParams(this.uri, this.diagnostics) {
+ if (uri == null) {
+ throw 'uri is required but was not provided';
+ }
+ if (diagnostics == null) {
+ throw 'diagnostics is required but was not provided';
+ }
+ }
+ factory PublishDiagnosticsParams.fromJson(Map<String, dynamic> json) {
+ final uri = json['uri'];
+ final diagnostics = json['diagnostics']
+ ?.map((item) => new Diagnostic.fromJson(item))
+ ?.cast<Diagnostic>()
+ ?.toList();
+ return new PublishDiagnosticsParams(uri, diagnostics);
+ }
/// An array of diagnostic information items.
final List<Diagnostic> diagnostics;
@@ -2156,10 +4312,41 @@
diagnostics ?? (throw 'diagnostics is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('uri') || !map['uri'] is String) {
+ return false;
+ }
+ if (!map.containsKey('diagnostics') ||
+ !(map['diagnostics'] is List &&
+ (map['diagnostics'].length == 0 ||
+ map['diagnostics']
+ .every((item) => Diagnostic.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['uri', 'diagnostics'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class Range {
- Range(this.start, this.end);
+ Range(this.start, this.end) {
+ if (start == null) {
+ throw 'start is required but was not provided';
+ }
+ if (end == null) {
+ throw 'end is required but was not provided';
+ }
+ }
+ factory Range.fromJson(Map<String, dynamic> json) {
+ final start = new Position.fromJson(json['start']);
+ final end = new Position.fromJson(json['end']);
+ return new Range(start, end);
+ }
/// The range's end position.
final Position end;
@@ -2173,10 +4360,33 @@
__result['end'] = end ?? (throw 'end is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('start') || !Position.canParse(map['start'])) {
+ return false;
+ }
+ if (!map.containsKey('end') || !Position.canParse(map['end'])) {
+ return false;
+ }
+ const validFieldNames = ['start', 'end'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ReferenceContext {
- ReferenceContext(this.includeDeclaration);
+ ReferenceContext(this.includeDeclaration) {
+ if (includeDeclaration == null) {
+ throw 'includeDeclaration is required but was not provided';
+ }
+ }
+ factory ReferenceContext.fromJson(Map<String, dynamic> json) {
+ final includeDeclaration = json['includeDeclaration'];
+ return new ReferenceContext(includeDeclaration);
+ }
/// Include the declaration of the current symbol.
final bool includeDeclaration;
@@ -2187,10 +4397,40 @@
(throw 'includeDeclaration is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('includeDeclaration') ||
+ !map['includeDeclaration'] is bool) {
+ return false;
+ }
+ const validFieldNames = ['includeDeclaration'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ReferenceParams implements TextDocumentPositionParams {
- ReferenceParams(this.context, this.textDocument, this.position);
+ ReferenceParams(this.context, this.textDocument, this.position) {
+ if (context == null) {
+ throw 'context is required but was not provided';
+ }
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (position == null) {
+ throw 'position is required but was not provided';
+ }
+ }
+ factory ReferenceParams.fromJson(Map<String, dynamic> json) {
+ final context = new ReferenceContext.fromJson(json['context']);
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ final position = new Position.fromJson(json['position']);
+ return new ReferenceParams(context, textDocument, position);
+ }
final ReferenceContext context;
@@ -2210,14 +4450,47 @@
position ?? (throw 'position is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('context') ||
+ !ReferenceContext.canParse(map['context'])) {
+ return false;
+ }
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('position') || !Position.canParse(map['position'])) {
+ return false;
+ }
+ const validFieldNames = ['context', 'textDocument', 'position'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// General parameters to register for a capability.
class Registration {
- Registration(this.id, this.method, this.registerOptions);
+ Registration(this.id, this.method, this.registerOptions) {
+ if (id == null) {
+ throw 'id is required but was not provided';
+ }
+ if (method == null) {
+ throw 'method is required but was not provided';
+ }
+ }
+ factory Registration.fromJson(Map<String, dynamic> json) {
+ final id = json['id'];
+ final method = json['method'];
+ final registerOptions = json['registerOptions'];
+ return new Registration(id, method, registerOptions);
+ }
- /// The id used to register the request. The id can be used to deregister the
- /// request again.
+ /// The id used to register the request. The id can be
+ /// used to deregister the request again.
final String id;
/// The method / capability to register for.
@@ -2235,10 +4508,36 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('id') || !map['id'] is String) {
+ return false;
+ }
+ if (!map.containsKey('method') || !map['method'] is String) {
+ return false;
+ }
+ const validFieldNames = ['id', 'method', 'registerOptions'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class RegistrationParams {
- RegistrationParams(this.registrations);
+ RegistrationParams(this.registrations) {
+ if (registrations == null) {
+ throw 'registrations is required but was not provided';
+ }
+ }
+ factory RegistrationParams.fromJson(Map<String, dynamic> json) {
+ final registrations = json['registrations']
+ ?.map((item) => new Registration.fromJson(item))
+ ?.cast<Registration>()
+ ?.toList();
+ return new RegistrationParams(registrations);
+ }
final List<Registration> registrations;
@@ -2248,11 +4547,40 @@
registrations ?? (throw 'registrations is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('registrations') ||
+ !(map['registrations'] is List &&
+ (map['registrations'].length == 0 ||
+ map['registrations']
+ .every((item) => Registration.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['registrations'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Rename file operation
class RenameFile implements FileOperation {
- RenameFile(this.oldUri, this.newUri, this.options);
+ RenameFile(this.oldUri, this.newUri, this.options) {
+ if (oldUri == null) {
+ throw 'oldUri is required but was not provided';
+ }
+ if (newUri == null) {
+ throw 'newUri is required but was not provided';
+ }
+ }
+ factory RenameFile.fromJson(Map<String, dynamic> json) {
+ final oldUri = json['oldUri'];
+ final newUri = json['newUri'];
+ final options = new RenameFileOptions.fromJson(json['options']);
+ return new RenameFile(oldUri, newUri, options);
+ }
/// The new location.
final String newUri;
@@ -2272,16 +4600,37 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('oldUri') || !map['oldUri'] is String) {
+ return false;
+ }
+ if (!map.containsKey('newUri') || !map['newUri'] is String) {
+ return false;
+ }
+ const validFieldNames = ['oldUri', 'newUri', 'options'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Rename file options
class RenameFileOptions {
RenameFileOptions(this.overwrite, this.ignoreIfExists);
+ factory RenameFileOptions.fromJson(Map<String, dynamic> json) {
+ final overwrite = json['overwrite'];
+ final ignoreIfExists = json['ignoreIfExists'];
+ return new RenameFileOptions(overwrite, ignoreIfExists);
+ }
/// Ignores if target exists.
final bool ignoreIfExists;
- /// Overwrite target if existing. Overwrite wins over `ignoreIfExists`
+ /// Overwrite target if existing. Overwrite wins over
+ /// `ignoreIfExists`
final bool overwrite;
Map<String, dynamic> toJson() {
@@ -2294,13 +4643,27 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['overwrite', 'ignoreIfExists'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Rename options
class RenameOptions {
RenameOptions(this.prepareProvider);
+ factory RenameOptions.fromJson(Map<String, dynamic> json) {
+ final prepareProvider = json['prepareProvider'];
+ return new RenameOptions(prepareProvider);
+ }
- /// Renames should be checked and tested before being executed.
+ /// Renames should be checked and tested before being
+ /// executed.
final bool prepareProvider;
Map<String, dynamic> toJson() {
@@ -2310,13 +4673,40 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['prepareProvider'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class RenameParams {
- RenameParams(this.textDocument, this.position, this.newName);
+ RenameParams(this.textDocument, this.position, this.newName) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (position == null) {
+ throw 'position is required but was not provided';
+ }
+ if (newName == null) {
+ throw 'newName is required but was not provided';
+ }
+ }
+ factory RenameParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ final position = new Position.fromJson(json['position']);
+ final newName = json['newName'];
+ return new RenameParams(textDocument, position, newName);
+ }
- /// The new name of the symbol. If the given name is not valid the request
- /// must return a [ResponseError] with an appropriate message set.
+ /// The new name of the symbol. If the given name is not
+ /// valid the request must return a [ResponseError] with
+ /// an appropriate message set.
final String newName;
/// The position at which this request was sent.
@@ -2335,16 +4725,45 @@
newName ?? (throw 'newName is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('position') || !Position.canParse(map['position'])) {
+ return false;
+ }
+ if (!map.containsKey('newName') || !map['newName'] is String) {
+ return false;
+ }
+ const validFieldNames = ['textDocument', 'position', 'newName'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class RenameRegistrationOptions implements TextDocumentRegistrationOptions {
RenameRegistrationOptions(this.prepareProvider, this.documentSelector);
+ factory RenameRegistrationOptions.fromJson(Map<String, dynamic> json) {
+ final prepareProvider = json['prepareProvider'];
+ final documentSelector = json['documentSelector']
+ ?.map((item) => new DocumentFilter.fromJson(item))
+ ?.cast<DocumentFilter>()
+ ?.toList();
+ return new RenameRegistrationOptions(prepareProvider, documentSelector);
+ }
- /// A document selector to identify the scope of the registration. If set to
- /// null the document selector provided on the client side will be used.
+ /// A document selector to identify the scope of the
+ /// registration. If set to null the document selector
+ /// provided on the client side will be used.
final List<DocumentFilter> documentSelector;
- /// Renames should be checked and tested for validity before being executed.
+ /// Renames should be checked and tested for validity
+ /// before being executed.
final bool prepareProvider;
Map<String, dynamic> toJson() {
@@ -2355,10 +4774,46 @@
__result['documentSelector'] = documentSelector;
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('documentSelector') ||
+ !(map['documentSelector'] is List &&
+ (map['documentSelector'].length == 0 ||
+ map['documentSelector']
+ .every((item) => DocumentFilter.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['prepareProvider', 'documentSelector'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class RequestMessage implements Message {
- RequestMessage(this.id, this.method, this.jsonrpc);
+ RequestMessage(this.id, this.method, this.jsonrpc) {
+ if (id == null) {
+ throw 'id is required but was not provided';
+ }
+ if (method == null) {
+ throw 'method is required but was not provided';
+ }
+ if (jsonrpc == null) {
+ throw 'jsonrpc is required but was not provided';
+ }
+ }
+ factory RequestMessage.fromJson(Map<String, dynamic> json) {
+ final id = json['id'] is num
+ ? new Either2<num, String>.t1(json['id'])
+ : (json['id'] is String
+ ? new Either2<num, String>.t2(json['id'])
+ : (throw '''${json['id']} was not one of (number, string)'''));
+ final method = json['method'];
+ final jsonrpc = json['jsonrpc'];
+ return new RequestMessage(id, method, jsonrpc);
+ }
/// The request id.
final Either2<num, String> id;
@@ -2375,13 +4830,42 @@
jsonrpc ?? (throw 'jsonrpc is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('id') || !(map['id'] is num || map['id'] is String)) {
+ return false;
+ }
+ if (!map.containsKey('method') || !map['method'] is String) {
+ return false;
+ }
+ if (!map.containsKey('jsonrpc') || !map['jsonrpc'] is String) {
+ return false;
+ }
+ const validFieldNames = ['id', 'method', 'jsonrpc'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ResourceOperationKind {
const ResourceOperationKind._(this._value);
+ const ResourceOperationKind.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 'create':
+ case 'rename':
+ case 'delete':
+ return true;
+ }
+ return false;
+ }
+
/// Supports creating new files and folders.
static const Create = const ResourceOperationKind._('create');
@@ -2403,13 +4887,28 @@
}
class ResponseMessage implements Message {
- ResponseMessage(this.id, this.result, this.jsonrpc);
+ ResponseMessage(this.id, this.result, this.jsonrpc) {
+ if (jsonrpc == null) {
+ throw 'jsonrpc is required but was not provided';
+ }
+ }
+ factory ResponseMessage.fromJson(Map<String, dynamic> json) {
+ final id = json['id'] is num
+ ? new Either2<num, String>.t1(json['id'])
+ : (json['id'] is String
+ ? new Either2<num, String>.t2(json['id'])
+ : (throw '''${json['id']} was not one of (number, string)'''));
+ final result = json['result'];
+ final jsonrpc = json['jsonrpc'];
+ return new ResponseMessage(id, result, jsonrpc);
+ }
/// The request id.
final Either2<num, String> id;
final String jsonrpc;
- /// The result of a request. This can be omitted in the case of an error.
+ /// The result of a request. This can be omitted in the
+ /// case of an error.
final dynamic result;
Map<String, dynamic> toJson() {
@@ -2422,13 +4921,33 @@
jsonrpc ?? (throw 'jsonrpc is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('id') || !(map['id'] is num || map['id'] is String)) {
+ return false;
+ }
+ if (!map.containsKey('jsonrpc') || !map['jsonrpc'] is String) {
+ return false;
+ }
+ const validFieldNames = ['id', 'result', 'jsonrpc'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Save options.
class SaveOptions {
SaveOptions(this.includeText);
+ factory SaveOptions.fromJson(Map<String, dynamic> json) {
+ final includeText = json['includeText'];
+ return new SaveOptions(includeText);
+ }
- /// The client is supposed to include the content on save.
+ /// The client is supposed to include the content on
+ /// save.
final bool includeText;
Map<String, dynamic> toJson() {
@@ -2438,6 +4957,15 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['includeText'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ServerCapabilities {
@@ -2461,18 +4989,92 @@
this.executeCommandProvider,
this.supported,
this.changeNotifications);
+ factory ServerCapabilities.fromJson(Map<String, dynamic> json) {
+ final textDocumentSync = TextDocumentSyncOptions.canParse(
+ json['textDocumentSync'])
+ ? new Either2<TextDocumentSyncOptions, num>.t1(
+ new TextDocumentSyncOptions.fromJson(json['textDocumentSync']))
+ : (json['textDocumentSync'] is num
+ ? new Either2<TextDocumentSyncOptions, num>.t2(
+ json['textDocumentSync'])
+ : (throw '''${json['textDocumentSync']} was not one of (TextDocumentSyncOptions, number)'''));
+ final hoverProvider = json['hoverProvider'];
+ final completionProvider =
+ new CompletionOptions.fromJson(json['completionProvider']);
+ final signatureHelpProvider =
+ new SignatureHelpOptions.fromJson(json['signatureHelpProvider']);
+ final definitionProvider = json['definitionProvider'];
+ final referencesProvider = json['referencesProvider'];
+ final documentHighlightProvider = json['documentHighlightProvider'];
+ final documentSymbolProvider = json['documentSymbolProvider'];
+ final workspaceSymbolProvider = json['workspaceSymbolProvider'];
+ final codeActionProvider = json['codeActionProvider'] is bool
+ ? new Either2<bool, CodeActionOptions>.t1(json['codeActionProvider'])
+ : (CodeActionOptions.canParse(json['codeActionProvider'])
+ ? new Either2<bool, CodeActionOptions>.t2(
+ new CodeActionOptions.fromJson(json['codeActionProvider']))
+ : (throw '''${json['codeActionProvider']} was not one of (boolean, CodeActionOptions)'''));
+ final codeLensProvider =
+ new CodeLensOptions.fromJson(json['codeLensProvider']);
+ final documentFormattingProvider = json['documentFormattingProvider'];
+ final documentRangeFormattingProvider =
+ json['documentRangeFormattingProvider'];
+ final documentOnTypeFormattingProvider =
+ new DocumentOnTypeFormattingOptions.fromJson(
+ json['documentOnTypeFormattingProvider']);
+ final renameProvider = json['renameProvider'] is bool
+ ? new Either2<bool, RenameOptions>.t1(json['renameProvider'])
+ : (RenameOptions.canParse(json['renameProvider'])
+ ? new Either2<bool, RenameOptions>.t2(
+ new RenameOptions.fromJson(json['renameProvider']))
+ : (throw '''${json['renameProvider']} was not one of (boolean, RenameOptions)'''));
+ final documentLinkProvider =
+ new DocumentLinkOptions.fromJson(json['documentLinkProvider']);
+ final executeCommandProvider =
+ new ExecuteCommandOptions.fromJson(json['executeCommandProvider']);
+ final supported = json['supported'];
+ final changeNotifications = json['changeNotifications'] is String
+ ? new Either2<String, bool>.t1(json['changeNotifications'])
+ : (json['changeNotifications'] is bool
+ ? new Either2<String, bool>.t2(json['changeNotifications'])
+ : (throw '''${json['changeNotifications']} was not one of (string, boolean)'''));
+ return new ServerCapabilities(
+ textDocumentSync,
+ hoverProvider,
+ completionProvider,
+ signatureHelpProvider,
+ definitionProvider,
+ referencesProvider,
+ documentHighlightProvider,
+ documentSymbolProvider,
+ workspaceSymbolProvider,
+ codeActionProvider,
+ codeLensProvider,
+ documentFormattingProvider,
+ documentRangeFormattingProvider,
+ documentOnTypeFormattingProvider,
+ renameProvider,
+ documentLinkProvider,
+ executeCommandProvider,
+ supported,
+ changeNotifications);
+ }
- /// Whether the server wants to receive workspace folder change notifications.
+ /// Whether the server wants to receive workspace folder
+ /// change notifications.
///
- /// If a strings is provided the string is treated as a ID under which the
- /// notification is registered on the client side. The ID can be used to
- /// unregister for these events using the `client/unregisterCapability`
+ /// If a strings is provided the string is treated as a
+ /// ID under which the notification is registered on the
+ /// client side. The ID can be used to unregister for
+ /// these events using the `client/unregisterCapability`
/// request.
final Either2<String, bool> changeNotifications;
- /// The server provides code actions. The `CodeActionOptions` return type is
- /// only valid if the client signals code action literal support via the
- /// property `textDocument.codeAction.codeActionLiteralSupport`.
+ /// The server provides code actions. The
+ /// `CodeActionOptions` return type is only valid if the
+ /// client signals code action literal support via the
+ /// property
+ /// `textDocument.codeAction.codeActionLiteralSupport`.
final Either2<bool, CodeActionOptions> codeActionProvider;
/// The server provides code lens.
@@ -2511,8 +5113,9 @@
/// The server provides find references support.
final bool referencesProvider;
- /// The server provides rename support. RenameOptions may only be specified if
- /// the client states that it supports `prepareSupport` in its initial
+ /// The server provides rename support. RenameOptions
+ /// may only be specified if the client states that it
+ /// supports `prepareSupport` in its initial
/// `initialize` request.
final Either2<bool, RenameOptions> renameProvider;
@@ -2522,9 +5125,10 @@
/// The server has support for workspace folders
final bool supported;
- /// Defines how text documents are synced. Is either a detailed structure
- /// defining each notification or for backwards compatibility the
- /// TextDocumentSyncKind number. If omitted it defaults to
+ /// Defines how text documents are synced. Is either a
+ /// detailed structure defining each notification or for
+ /// backwards compatibility the TextDocumentSyncKind
+ /// number. If omitted it defaults to
/// `TextDocumentSyncKind.None`.
final Either2<TextDocumentSyncOptions, num> textDocumentSync;
@@ -2594,10 +5198,51 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = [
+ 'textDocumentSync',
+ 'hoverProvider',
+ 'completionProvider',
+ 'signatureHelpProvider',
+ 'definitionProvider',
+ 'referencesProvider',
+ 'documentHighlightProvider',
+ 'documentSymbolProvider',
+ 'workspaceSymbolProvider',
+ 'codeActionProvider',
+ 'codeLensProvider',
+ 'documentFormattingProvider',
+ 'documentRangeFormattingProvider',
+ 'documentOnTypeFormattingProvider',
+ 'renameProvider',
+ 'documentLinkProvider',
+ 'executeCommandProvider',
+ 'supported',
+ 'changeNotifications'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ShowMessageParams {
- ShowMessageParams(this.type, this.message);
+ ShowMessageParams(this.type, this.message) {
+ if (type == null) {
+ throw 'type is required but was not provided';
+ }
+ if (message == null) {
+ throw 'message is required but was not provided';
+ }
+ }
+ factory ShowMessageParams.fromJson(Map<String, dynamic> json) {
+ final type = new MessageType.fromJson(json['type']);
+ final message = json['message'];
+ return new ShowMessageParams(type, message);
+ }
/// The actual message.
final String message;
@@ -2612,10 +5257,41 @@
message ?? (throw 'message is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('type') || !MessageType.canParse(map['type'])) {
+ return false;
+ }
+ if (!map.containsKey('message') || !map['message'] is String) {
+ return false;
+ }
+ const validFieldNames = ['type', 'message'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class ShowMessageRequestParams {
- ShowMessageRequestParams(this.type, this.message, this.actions);
+ ShowMessageRequestParams(this.type, this.message, this.actions) {
+ if (type == null) {
+ throw 'type is required but was not provided';
+ }
+ if (message == null) {
+ throw 'message is required but was not provided';
+ }
+ }
+ factory ShowMessageRequestParams.fromJson(Map<String, dynamic> json) {
+ final type = new MessageType.fromJson(json['type']);
+ final message = json['message'];
+ final actions = json['actions']
+ ?.map((item) => new MessageActionItem.fromJson(item))
+ ?.cast<MessageActionItem>()
+ ?.toList();
+ return new ShowMessageRequestParams(type, message, actions);
+ }
/// The message action items to present.
final List<MessageActionItem> actions;
@@ -2636,27 +5312,60 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('type') || !MessageType.canParse(map['type'])) {
+ return false;
+ }
+ if (!map.containsKey('message') || !map['message'] is String) {
+ return false;
+ }
+ const validFieldNames = ['type', 'message', 'actions'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// Signature help represents the signature of something callable. There can be
-/// multiple signature but only one active and only one active parameter.
+/// Signature help represents the signature of something
+/// callable. There can be multiple signature but only one
+/// active and only one active parameter.
class SignatureHelp {
- SignatureHelp(this.signatures, this.activeSignature, this.activeParameter);
+ SignatureHelp(this.signatures, this.activeSignature, this.activeParameter) {
+ if (signatures == null) {
+ throw 'signatures is required but was not provided';
+ }
+ }
+ factory SignatureHelp.fromJson(Map<String, dynamic> json) {
+ final signatures = json['signatures']
+ ?.map((item) => new SignatureInformation.fromJson(item))
+ ?.cast<SignatureInformation>()
+ ?.toList();
+ final activeSignature = json['activeSignature'];
+ final activeParameter = json['activeParameter'];
+ return new SignatureHelp(signatures, activeSignature, activeParameter);
+ }
- /// The active parameter of the active signature. If omitted or the value lies
- /// outside the range of `signatures[activeSignature].parameters` defaults to
- /// 0 if the active signature has parameters. If the active signature has no
- /// parameters it is ignored. In future version of the protocol this property
- /// might become mandatory to better express the active parameter if the
- /// active signature does have any.
+ /// The active parameter of the active signature. If
+ /// omitted or the value lies outside the range of
+ /// `signatures[activeSignature].parameters` defaults to
+ /// 0 if the active signature has parameters. If the
+ /// active signature has no parameters it is ignored. In
+ /// future version of the protocol this property might
+ /// become mandatory to better express the active
+ /// parameter if the active signature does have any.
final num activeParameter;
- /// The active signature. If omitted or the value lies outside the range of
- /// `signatures` the value defaults to zero or is ignored if
- /// `signatures.length === 0`. Whenever possible implementors should make an
- /// active decision about the active signature and shouldn't rely on a default
- /// value. In future version of the protocol this property might become
- /// mandatory to better express this.
+ /// The active signature. If omitted or the value lies
+ /// outside the range of `signatures` the value defaults
+ /// to zero or is ignored if `signatures.length === 0`.
+ /// Whenever possible implementors should make an active
+ /// decision about the active signature and shouldn't
+ /// rely on a default value. In future version of the
+ /// protocol this property might become mandatory to
+ /// better express this.
final num activeSignature;
/// One or more signatures.
@@ -2674,13 +5383,41 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('signatures') ||
+ !(map['signatures'] is List &&
+ (map['signatures'].length == 0 ||
+ map['signatures']
+ .every((item) => SignatureInformation.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = [
+ 'signatures',
+ 'activeSignature',
+ 'activeParameter'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Signature help options.
class SignatureHelpOptions {
SignatureHelpOptions(this.triggerCharacters);
+ factory SignatureHelpOptions.fromJson(Map<String, dynamic> json) {
+ final triggerCharacters = json['triggerCharacters']
+ ?.map((item) => item)
+ ?.cast<String>()
+ ?.toList();
+ return new SignatureHelpOptions(triggerCharacters);
+ }
- /// The characters that trigger signature help automatically.
+ /// The characters that trigger signature help
+ /// automatically.
final List<String> triggerCharacters;
Map<String, dynamic> toJson() {
@@ -2690,18 +5427,41 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['triggerCharacters'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class SignatureHelpRegistrationOptions
implements TextDocumentRegistrationOptions {
SignatureHelpRegistrationOptions(
this.triggerCharacters, this.documentSelector);
+ factory SignatureHelpRegistrationOptions.fromJson(Map<String, dynamic> json) {
+ final triggerCharacters = json['triggerCharacters']
+ ?.map((item) => item)
+ ?.cast<String>()
+ ?.toList();
+ final documentSelector = json['documentSelector']
+ ?.map((item) => new DocumentFilter.fromJson(item))
+ ?.cast<DocumentFilter>()
+ ?.toList();
+ return new SignatureHelpRegistrationOptions(
+ triggerCharacters, documentSelector);
+ }
- /// A document selector to identify the scope of the registration. If set to
- /// null the document selector provided on the client side will be used.
+ /// A document selector to identify the scope of the
+ /// registration. If set to null the document selector
+ /// provided on the client side will be used.
final List<DocumentFilter> documentSelector;
- /// The characters that trigger signature help automatically.
+ /// The characters that trigger signature help
+ /// automatically.
final List<String> triggerCharacters;
Map<String, dynamic> toJson() {
@@ -2712,18 +5472,54 @@
__result['documentSelector'] = documentSelector;
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('documentSelector') ||
+ !(map['documentSelector'] is List &&
+ (map['documentSelector'].length == 0 ||
+ map['documentSelector']
+ .every((item) => DocumentFilter.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['triggerCharacters', 'documentSelector'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// Represents the signature of something callable. A signature can have a
-/// label, like a function-name, a doc-comment, and a set of parameters.
+/// Represents the signature of something callable. A
+/// signature can have a label, like a function-name, a
+/// doc-comment, and a set of parameters.
class SignatureInformation {
- SignatureInformation(this.label, this.documentation, this.parameters);
+ SignatureInformation(this.label, this.documentation, this.parameters) {
+ if (label == null) {
+ throw 'label is required but was not provided';
+ }
+ }
+ factory SignatureInformation.fromJson(Map<String, dynamic> json) {
+ final label = json['label'];
+ final documentation = json['documentation'] is String
+ ? new Either2<String, MarkupContent>.t1(json['documentation'])
+ : (MarkupContent.canParse(json['documentation'])
+ ? new Either2<String, MarkupContent>.t2(
+ new MarkupContent.fromJson(json['documentation']))
+ : (throw '''${json['documentation']} was not one of (string, MarkupContent)'''));
+ final parameters = json['parameters']
+ ?.map((item) => new ParameterInformation.fromJson(item))
+ ?.cast<ParameterInformation>()
+ ?.toList();
+ return new SignatureInformation(label, documentation, parameters);
+ }
- /// The human-readable doc-comment of this signature. Will be shown in the UI
- /// but can be omitted.
+ /// The human-readable doc-comment of this signature.
+ /// Will be shown in the UI but can be omitted.
final Either2<String, MarkupContent> documentation;
- /// The label of this signature. Will be shown in the UI.
+ /// The label of this signature. Will be shown in the
+ /// UI.
final String label;
/// The parameters of this signature.
@@ -2740,14 +5536,32 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('label') || !map['label'] is String) {
+ return false;
+ }
+ const validFieldNames = ['label', 'documentation', 'parameters'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// Static registration options to be returned in the initialize request.
+/// Static registration options to be returned in the
+/// initialize request.
class StaticRegistrationOptions {
StaticRegistrationOptions(this.id);
+ factory StaticRegistrationOptions.fromJson(Map<String, dynamic> json) {
+ final id = json['id'];
+ return new StaticRegistrationOptions(id);
+ }
- /// The id used to register the request. The id can be used to deregister the
- /// request again. See also Registration#id.
+ /// The id used to register the request. The id can be
+ /// used to deregister the request again. See also
+ /// Registration#id.
final String id;
Map<String, dynamic> toJson() {
@@ -2757,18 +5571,47 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['id'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// Represents information about programming constructs like variables, classes,
-/// interfaces etc.
+/// Represents information about programming constructs
+/// like variables, classes, interfaces etc.
class SymbolInformation {
- SymbolInformation(
- this.name, this.kind, this.deprecated, this.location, this.containerName);
+ SymbolInformation(this.name, this.kind, this.deprecated, this.location,
+ this.containerName) {
+ if (name == null) {
+ throw 'name is required but was not provided';
+ }
+ if (kind == null) {
+ throw 'kind is required but was not provided';
+ }
+ if (location == null) {
+ throw 'location is required but was not provided';
+ }
+ }
+ factory SymbolInformation.fromJson(Map<String, dynamic> json) {
+ final name = json['name'];
+ final kind = json['kind'];
+ final deprecated = json['deprecated'];
+ final location = new Location.fromJson(json['location']);
+ final containerName = json['containerName'];
+ return new SymbolInformation(
+ name, kind, deprecated, location, containerName);
+ }
- /// The name of the symbol containing this symbol. This information is for
- /// user interface purposes (e.g. to render a qualifier in the user interface
- /// if necessary). It can't be used to re-infer a hierarchy for the document
- /// symbols.
+ /// The name of the symbol containing this symbol. This
+ /// information is for user interface purposes (e.g. to
+ /// render a qualifier in the user interface if
+ /// necessary). It can't be used to re-infer a hierarchy
+ /// for the document symbols.
final String containerName;
/// Indicates if this symbol is deprecated.
@@ -2777,15 +5620,18 @@
/// The kind of this symbol.
final num kind;
- /// The location of this symbol. The location's range is used by a tool to
- /// reveal the location in the editor. If the symbol is selected in the tool
- /// the range's start information is used to position the cursor. So the range
- /// usually spans more then the actual symbol's name and does normally include
- /// things like visibility modifiers.
+ /// The location of this symbol. The location's range is
+ /// used by a tool to reveal the location in the editor.
+ /// If the symbol is selected in the tool the range's
+ /// start information is used to position the cursor. So
+ /// the range usually spans more then the actual
+ /// symbol's name and does normally include things like
+ /// visibility modifiers.
///
- /// The range doesn't have to denote a node range in the sense of a abstract
- /// syntax tree. It can therefore not be used to re-construct a hierarchy of
- /// the symbols.
+ /// The range doesn't have to denote a node range in the
+ /// sense of a abstract syntax tree. It can therefore
+ /// not be used to re-construct a hierarchy of the
+ /// symbols.
final Location location;
/// The name of this symbol.
@@ -2805,14 +5651,72 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('name') || !map['name'] is String) {
+ return false;
+ }
+ if (!map.containsKey('kind') || !map['kind'] is num) {
+ return false;
+ }
+ if (!map.containsKey('location') || !Location.canParse(map['location'])) {
+ return false;
+ }
+ const validFieldNames = [
+ 'name',
+ 'kind',
+ 'deprecated',
+ 'location',
+ 'containerName'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// A symbol kind.
class SymbolKind {
const SymbolKind._(this._value);
+ const SymbolKind.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ return true;
+ }
+ return false;
+ }
+
static const File = const SymbolKind._(1);
static const Module = const SymbolKind._(2);
static const Namespace = const SymbolKind._(3);
@@ -2851,17 +5755,33 @@
bool operator ==(o) => o is SymbolKind && o._value == _value;
}
-/// Describe options to be used when registering for text document change
-/// events.
+/// Describe options to be used when registering for
+/// text document change events.
class TextDocumentChangeRegistrationOptions
implements TextDocumentRegistrationOptions {
- TextDocumentChangeRegistrationOptions(this.syncKind, this.documentSelector);
+ TextDocumentChangeRegistrationOptions(this.syncKind, this.documentSelector) {
+ if (syncKind == null) {
+ throw 'syncKind is required but was not provided';
+ }
+ }
+ factory TextDocumentChangeRegistrationOptions.fromJson(
+ Map<String, dynamic> json) {
+ final syncKind = json['syncKind'];
+ final documentSelector = json['documentSelector']
+ ?.map((item) => new DocumentFilter.fromJson(item))
+ ?.cast<DocumentFilter>()
+ ?.toList();
+ return new TextDocumentChangeRegistrationOptions(
+ syncKind, documentSelector);
+ }
- /// A document selector to identify the scope of the registration. If set to
- /// null the document selector provided on the client side will be used.
+ /// A document selector to identify the scope of the
+ /// registration. If set to null the document selector
+ /// provided on the client side will be used.
final List<DocumentFilter> documentSelector;
- /// How documents are synced to the server. See TextDocumentSyncKind.Full and
+ /// How documents are synced to the server. See
+ /// TextDocumentSyncKind.Full and
/// TextDocumentSyncKind.Incremental.
final num syncKind;
@@ -2872,24 +5792,54 @@
__result['documentSelector'] = documentSelector;
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('syncKind') || !map['syncKind'] is num) {
+ return false;
+ }
+ if (!map.containsKey('documentSelector') ||
+ !(map['documentSelector'] is List &&
+ (map['documentSelector'].length == 0 ||
+ map['documentSelector']
+ .every((item) => DocumentFilter.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['syncKind', 'documentSelector'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Text document specific client capabilities.
class TextDocumentClientCapabilities {
TextDocumentClientCapabilities(this.dynamicRegistration, this.willSave,
this.willSaveWaitUntil, this.didSave);
+ factory TextDocumentClientCapabilities.fromJson(Map<String, dynamic> json) {
+ final dynamicRegistration = json['dynamicRegistration'];
+ final willSave = json['willSave'];
+ final willSaveWaitUntil = json['willSaveWaitUntil'];
+ final didSave = json['didSave'];
+ return new TextDocumentClientCapabilities(
+ dynamicRegistration, willSave, willSaveWaitUntil, didSave);
+ }
/// The client supports did save notifications.
final bool didSave;
- /// Whether text document synchronization supports dynamic registration.
+ /// Whether text document synchronization supports
+ /// dynamic registration.
final bool dynamicRegistration;
- /// The client supports sending will save notifications.
+ /// The client supports sending will save
+ /// notifications.
final bool willSave;
- /// The client supports sending a will save request and waits for a response
- /// providing text edits which will be applied to the document before it is
+ /// The client supports sending a will save request
+ /// and waits for a response providing text edits
+ /// which will be applied to the document before it is
/// saved.
final bool willSaveWaitUntil;
@@ -2909,13 +5859,37 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = [
+ 'dynamicRegistration',
+ 'willSave',
+ 'willSaveWaitUntil',
+ 'didSave'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// An event describing a change to a text document. If range and rangeLength
-/// are omitted the new text is considered to be the full content of the
-/// document.
+/// An event describing a change to a text document. If
+/// range and rangeLength are omitted the new text is
+/// considered to be the full content of the document.
class TextDocumentContentChangeEvent {
- TextDocumentContentChangeEvent(this.range, this.rangeLength, this.text);
+ TextDocumentContentChangeEvent(this.range, this.rangeLength, this.text) {
+ if (text == null) {
+ throw 'text is required but was not provided';
+ }
+ }
+ factory TextDocumentContentChangeEvent.fromJson(Map<String, dynamic> json) {
+ final range = new Range.fromJson(json['range']);
+ final rangeLength = json['rangeLength'];
+ final text = json['text'];
+ return new TextDocumentContentChangeEvent(range, rangeLength, text);
+ }
/// The range of the document that changed.
final Range range;
@@ -2937,10 +5911,38 @@
__result['text'] = text ?? (throw 'text is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('text') || !map['text'] is String) {
+ return false;
+ }
+ const validFieldNames = ['range', 'rangeLength', 'text'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class TextDocumentEdit implements FileOperation {
- TextDocumentEdit(this.textDocument, this.edits);
+ TextDocumentEdit(this.textDocument, this.edits) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (edits == null) {
+ throw 'edits is required but was not provided';
+ }
+ }
+ factory TextDocumentEdit.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new VersionedTextDocumentIdentifier.fromJson(json['textDocument']);
+ final edits = json['edits']
+ ?.map((item) => new TextEdit.fromJson(item))
+ ?.cast<TextEdit>()
+ ?.toList();
+ return new TextDocumentEdit(textDocument, edits);
+ }
/// The edits to be applied.
final List<TextEdit> edits;
@@ -2955,10 +5957,37 @@
__result['edits'] = edits ?? (throw 'edits is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !VersionedTextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('edits') ||
+ !(map['edits'] is List &&
+ (map['edits'].length == 0 ||
+ map['edits'].every((item) => TextEdit.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['textDocument', 'edits'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class TextDocumentIdentifier {
- TextDocumentIdentifier(this.uri);
+ TextDocumentIdentifier(this.uri) {
+ if (uri == null) {
+ throw 'uri is required but was not provided';
+ }
+ }
+ factory TextDocumentIdentifier.fromJson(Map<String, dynamic> json) {
+ final uri = json['uri'];
+ return new TextDocumentIdentifier(uri);
+ }
/// The text document's URI.
final String uri;
@@ -2968,10 +5997,42 @@
__result['uri'] = uri ?? (throw 'uri is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('uri') || !map['uri'] is String) {
+ return false;
+ }
+ const validFieldNames = ['uri'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class TextDocumentItem {
- TextDocumentItem(this.uri, this.languageId, this.version, this.text);
+ TextDocumentItem(this.uri, this.languageId, this.version, this.text) {
+ if (uri == null) {
+ throw 'uri is required but was not provided';
+ }
+ if (languageId == null) {
+ throw 'languageId is required but was not provided';
+ }
+ if (version == null) {
+ throw 'version is required but was not provided';
+ }
+ if (text == null) {
+ throw 'text is required but was not provided';
+ }
+ }
+ factory TextDocumentItem.fromJson(Map<String, dynamic> json) {
+ final uri = json['uri'];
+ final languageId = json['languageId'];
+ final version = json['version'];
+ final text = json['text'];
+ return new TextDocumentItem(uri, languageId, version, text);
+ }
/// The text document's language identifier.
final String languageId;
@@ -2982,8 +6043,8 @@
/// The text document's URI.
final String uri;
- /// The version number of this document (it will increase after each change,
- /// including undo/redo).
+ /// The version number of this document (it will
+ /// increase after each change, including undo/redo).
final num version;
Map<String, dynamic> toJson() {
@@ -2996,10 +6057,44 @@
__result['text'] = text ?? (throw 'text is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('uri') || !map['uri'] is String) {
+ return false;
+ }
+ if (!map.containsKey('languageId') || !map['languageId'] is String) {
+ return false;
+ }
+ if (!map.containsKey('version') || !map['version'] is num) {
+ return false;
+ }
+ if (!map.containsKey('text') || !map['text'] is String) {
+ return false;
+ }
+ const validFieldNames = ['uri', 'languageId', 'version', 'text'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class TextDocumentPositionParams {
- TextDocumentPositionParams(this.textDocument, this.position);
+ TextDocumentPositionParams(this.textDocument, this.position) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (position == null) {
+ throw 'position is required but was not provided';
+ }
+ }
+ factory TextDocumentPositionParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ final position = new Position.fromJson(json['position']);
+ return new TextDocumentPositionParams(textDocument, position);
+ }
/// The position inside the text document.
final Position position;
@@ -3015,13 +6110,37 @@
position ?? (throw 'position is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('position') || !Position.canParse(map['position'])) {
+ return false;
+ }
+ const validFieldNames = ['textDocument', 'position'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class TextDocumentRegistrationOptions {
TextDocumentRegistrationOptions(this.documentSelector);
+ factory TextDocumentRegistrationOptions.fromJson(Map<String, dynamic> json) {
+ final documentSelector = json['documentSelector']
+ ?.map((item) => new DocumentFilter.fromJson(item))
+ ?.cast<DocumentFilter>()
+ ?.toList();
+ return new TextDocumentRegistrationOptions(documentSelector);
+ }
- /// A document selector to identify the scope of the registration. If set to
- /// null the document selector provided on the client side will be used.
+ /// A document selector to identify the scope of the
+ /// registration. If set to null the document selector
+ /// provided on the client side will be used.
final List<DocumentFilter> documentSelector;
Map<String, dynamic> toJson() {
@@ -3029,16 +6148,43 @@
__result['documentSelector'] = documentSelector;
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('documentSelector') ||
+ !(map['documentSelector'] is List &&
+ (map['documentSelector'].length == 0 ||
+ map['documentSelector']
+ .every((item) => DocumentFilter.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['documentSelector'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Represents reasons why a text document is saved.
class TextDocumentSaveReason {
const TextDocumentSaveReason._(this._value);
+ const TextDocumentSaveReason.fromJson(this._value);
final Object _value;
- /// Manually triggered, e.g. by the user pressing save, by starting debugging,
- /// or by an API call.
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 1:
+ case 2:
+ case 3:
+ return true;
+ }
+ return false;
+ }
+
+ /// Manually triggered, e.g. by the user pressing
+ /// save, by starting debugging, or by an API call.
static const Manual = const TextDocumentSaveReason._(1);
/// Automatic after a delay.
@@ -3061,12 +6207,25 @@
class TextDocumentSaveRegistrationOptions
implements TextDocumentRegistrationOptions {
TextDocumentSaveRegistrationOptions(this.includeText, this.documentSelector);
+ factory TextDocumentSaveRegistrationOptions.fromJson(
+ Map<String, dynamic> json) {
+ final includeText = json['includeText'];
+ final documentSelector = json['documentSelector']
+ ?.map((item) => new DocumentFilter.fromJson(item))
+ ?.cast<DocumentFilter>()
+ ?.toList();
+ return new TextDocumentSaveRegistrationOptions(
+ includeText, documentSelector);
+ }
- /// A document selector to identify the scope of the registration. If set to
- /// null the document selector provided on the client side will be used.
+ /// A document selector to identify the scope of the
+ /// registration. If set to null the document
+ /// selector provided on the client side will be
+ /// used.
final List<DocumentFilter> documentSelector;
- /// The client is supposed to include the content on save.
+ /// The client is supposed to include the content on
+ /// save.
final bool includeText;
Map<String, dynamic> toJson() {
@@ -3077,23 +6236,52 @@
__result['documentSelector'] = documentSelector;
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('documentSelector') ||
+ !(map['documentSelector'] is List &&
+ (map['documentSelector'].length == 0 ||
+ map['documentSelector']
+ .every((item) => DocumentFilter.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['includeText', 'documentSelector'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
-/// Defines how the host (editor) should sync document changes to the language
-/// server.
+/// Defines how the host (editor) should sync document
+/// changes to the language server.
class TextDocumentSyncKind {
const TextDocumentSyncKind._(this._value);
+ const TextDocumentSyncKind.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 0:
+ case 1:
+ case 2:
+ return true;
+ }
+ return false;
+ }
+
/// Documents should not be synced at all.
static const None = const TextDocumentSyncKind._(0);
- /// Documents are synced by always sending the full content of the document.
+ /// Documents are synced by always sending the
+ /// full content of the document.
static const Full = const TextDocumentSyncKind._(1);
- /// Documents are synced by sending the full content on open. After that only
- /// incremental updates to the document are send.
+ /// Documents are synced by sending the full
+ /// content on open. After that only incremental
+ /// updates to the document are send.
static const Incremental = const TextDocumentSyncKind._(2);
Object toJson() => _value;
@@ -3110,23 +6298,36 @@
class TextDocumentSyncOptions {
TextDocumentSyncOptions(this.openClose, this.change, this.willSave,
this.willSaveWaitUntil, this.save);
+ factory TextDocumentSyncOptions.fromJson(Map<String, dynamic> json) {
+ final openClose = json['openClose'];
+ final change = new TextDocumentSyncKind.fromJson(json['change']);
+ final willSave = json['willSave'];
+ final willSaveWaitUntil = json['willSaveWaitUntil'];
+ final save = new SaveOptions.fromJson(json['save']);
+ return new TextDocumentSyncOptions(
+ openClose, change, willSave, willSaveWaitUntil, save);
+ }
- /// Change notifications are sent to the server. See
- /// TextDocumentSyncKind.None, TextDocumentSyncKind.Full and
- /// TextDocumentSyncKind.Incremental. If omitted it defaults to
- /// TextDocumentSyncKind.None.
+ /// Change notifications are sent to the server.
+ /// See TextDocumentSyncKind.None,
+ /// TextDocumentSyncKind.Full and
+ /// TextDocumentSyncKind.Incremental. If omitted
+ /// it defaults to TextDocumentSyncKind.None.
final TextDocumentSyncKind change;
- /// Open and close notifications are sent to the server.
+ /// Open and close notifications are sent to the
+ /// server.
final bool openClose;
/// Save notifications are sent to the server.
final SaveOptions save;
- /// Will save notifications are sent to the server.
+ /// Will save notifications are sent to the
+ /// server.
final bool willSave;
- /// Will save wait until requests are sent to the server.
+ /// Will save wait until requests are sent to the
+ /// server.
final bool willSaveWaitUntil;
Map<String, dynamic> toJson() {
@@ -3148,16 +6349,45 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = [
+ 'openClose',
+ 'change',
+ 'willSave',
+ 'willSaveWaitUntil',
+ 'save'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class TextEdit {
- TextEdit(this.range, this.newText);
+ TextEdit(this.range, this.newText) {
+ if (range == null) {
+ throw 'range is required but was not provided';
+ }
+ if (newText == null) {
+ throw 'newText is required but was not provided';
+ }
+ }
+ factory TextEdit.fromJson(Map<String, dynamic> json) {
+ final range = new Range.fromJson(json['range']);
+ final newText = json['newText'];
+ return new TextEdit(range, newText);
+ }
- /// The string to be inserted. For delete operations use an empty string.
+ /// The string to be inserted. For delete
+ /// operations use an empty string.
final String newText;
- /// The range of the text document to be manipulated. To insert text into a
- /// document create a range where start === end.
+ /// The range of the text document to be
+ /// manipulated. To insert text into a document
+ /// create a range where start === end.
final Range range;
Map<String, dynamic> toJson() {
@@ -3167,14 +6397,42 @@
newText ?? (throw 'newText is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('range') || !Range.canParse(map['range'])) {
+ return false;
+ }
+ if (!map.containsKey('newText') || !map['newText'] is String) {
+ return false;
+ }
+ const validFieldNames = ['range', 'newText'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// General parameters to unregister a capability.
class Unregistration {
- Unregistration(this.id, this.method);
+ Unregistration(this.id, this.method) {
+ if (id == null) {
+ throw 'id is required but was not provided';
+ }
+ if (method == null) {
+ throw 'method is required but was not provided';
+ }
+ }
+ factory Unregistration.fromJson(Map<String, dynamic> json) {
+ final id = json['id'];
+ final method = json['method'];
+ return new Unregistration(id, method);
+ }
- /// The id used to unregister the request or notification. Usually an id
- /// provided during the register request.
+ /// The id used to unregister the request or
+ /// notification. Usually an id provided during
+ /// the register request.
final String id;
/// The method / capability to unregister for.
@@ -3186,10 +6444,36 @@
__result['method'] = method ?? (throw 'method is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('id') || !map['id'] is String) {
+ return false;
+ }
+ if (!map.containsKey('method') || !map['method'] is String) {
+ return false;
+ }
+ const validFieldNames = ['id', 'method'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class UnregistrationParams {
- UnregistrationParams(this.unregisterations);
+ UnregistrationParams(this.unregisterations) {
+ if (unregisterations == null) {
+ throw 'unregisterations is required but was not provided';
+ }
+ }
+ factory UnregistrationParams.fromJson(Map<String, dynamic> json) {
+ final unregisterations = json['unregisterations']
+ ?.map((item) => new Unregistration.fromJson(item))
+ ?.cast<Unregistration>()
+ ?.toList();
+ return new UnregistrationParams(unregisterations);
+ }
final List<Unregistration> unregisterations;
@@ -3199,22 +6483,52 @@
(throw 'unregisterations is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('unregisterations') ||
+ !(map['unregisterations'] is List &&
+ (map['unregisterations'].length == 0 ||
+ map['unregisterations']
+ .every((item) => Unregistration.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['unregisterations'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class VersionedTextDocumentIdentifier implements TextDocumentIdentifier {
- VersionedTextDocumentIdentifier(this.version, this.uri);
+ VersionedTextDocumentIdentifier(this.version, this.uri) {
+ if (uri == null) {
+ throw 'uri is required but was not provided';
+ }
+ }
+ factory VersionedTextDocumentIdentifier.fromJson(Map<String, dynamic> json) {
+ final version = json['version'];
+ final uri = json['uri'];
+ return new VersionedTextDocumentIdentifier(version, uri);
+ }
/// The text document's URI.
final String uri;
- /// The version number of this document. If a versioned text document
- /// identifier is sent from the server to the client and the file is not open
- /// in the editor (the server has not received an open notification before)
- /// the server can send `null` to indicate that the version is known and the
- /// content on disk is the truth (as speced with document content ownership).
+ /// The version number of this document. If a
+ /// versioned text document identifier is sent
+ /// from the server to the client and the file is
+ /// not open in the editor (the server has not
+ /// received an open notification before) the
+ /// server can send `null` to indicate that the
+ /// version is known and the content on disk is
+ /// the truth (as speced with document content
+ /// ownership).
///
- /// The version number of a document will increase after each change,
- /// including undo/redo. The number doesn't need to be consecutive.
+ /// The version number of a document will increase
+ /// after each change, including undo/redo. The
+ /// number doesn't need to be consecutive.
final num version;
Map<String, dynamic> toJson() {
@@ -3223,13 +6537,39 @@
__result['uri'] = uri ?? (throw 'uri is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('version') || !map['version'] is num) {
+ return false;
+ }
+ if (!map.containsKey('uri') || !map['uri'] is String) {
+ return false;
+ }
+ const validFieldNames = ['version', 'uri'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class WatchKind {
const WatchKind._(this._value);
+ const WatchKind.fromJson(this._value);
final Object _value;
+ static bool canParse(Object obj) {
+ switch (obj) {
+ case 1:
+ case 2:
+ case 4:
+ return true;
+ }
+ return false;
+ }
+
/// Interested in create events.
static const Create = const WatchKind._(1);
@@ -3250,9 +6590,23 @@
bool operator ==(o) => o is WatchKind && o._value == _value;
}
-/// The parameters send in a will save text document notification.
+/// The parameters send in a will save text
+/// document notification.
class WillSaveTextDocumentParams {
- WillSaveTextDocumentParams(this.textDocument, this.reason);
+ WillSaveTextDocumentParams(this.textDocument, this.reason) {
+ if (textDocument == null) {
+ throw 'textDocument is required but was not provided';
+ }
+ if (reason == null) {
+ throw 'reason is required but was not provided';
+ }
+ }
+ factory WillSaveTextDocumentParams.fromJson(Map<String, dynamic> json) {
+ final textDocument =
+ new TextDocumentIdentifier.fromJson(json['textDocument']);
+ final reason = json['reason'];
+ return new WillSaveTextDocumentParams(textDocument, reason);
+ }
/// The 'TextDocumentSaveReason'.
final num reason;
@@ -3267,26 +6621,57 @@
__result['reason'] = reason ?? (throw 'reason is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('textDocument') ||
+ !TextDocumentIdentifier.canParse(map['textDocument'])) {
+ return false;
+ }
+ if (!map.containsKey('reason') || !map['reason'] is num) {
+ return false;
+ }
+ const validFieldNames = ['textDocument', 'reason'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// Workspace specific client capabilities.
class WorkspaceClientCapabilities {
WorkspaceClientCapabilities(this.applyEdit, this.documentChanges,
this.resourceOperations, this.failureHandling);
+ factory WorkspaceClientCapabilities.fromJson(Map<String, dynamic> json) {
+ final applyEdit = json['applyEdit'];
+ final documentChanges = json['documentChanges'];
+ final resourceOperations = json['resourceOperations']
+ ?.map((item) => new ResourceOperationKind.fromJson(item))
+ ?.cast<ResourceOperationKind>()
+ ?.toList();
+ final failureHandling =
+ new FailureHandlingKind.fromJson(json['failureHandling']);
+ return new WorkspaceClientCapabilities(
+ applyEdit, documentChanges, resourceOperations, failureHandling);
+ }
- /// The client supports applying batch edits to the workspace by supporting
- /// the request 'workspace/applyEdit'
+ /// The client supports applying batch edits to
+ /// the workspace by supporting the request
+ /// 'workspace/applyEdit'
final bool applyEdit;
- /// The client supports versioned document changes in `WorkspaceEdit`s
+ /// The client supports versioned document
+ /// changes in `WorkspaceEdit`s
final bool documentChanges;
- /// The failure handling strategy of a client if applying the workspace edit
- /// failes.
+ /// The failure handling strategy of a client if
+ /// applying the workspace edit failes.
final FailureHandlingKind failureHandling;
- /// The resource operations the client supports. Clients should at least
- /// support 'create', 'rename' and 'delete' files and folders.
+ /// The resource operations the client supports.
+ /// Clients should at least support 'create',
+ /// 'rename' and 'delete' files and folders.
final List<ResourceOperationKind> resourceOperations;
Map<String, dynamic> toJson() {
@@ -3305,27 +6690,56 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = [
+ 'applyEdit',
+ 'documentChanges',
+ 'resourceOperations',
+ 'failureHandling'
+ ];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class WorkspaceEdit {
WorkspaceEdit(this.changes, this.documentChanges);
+ factory WorkspaceEdit.fromJson(Map<String, dynamic> json) {
+ final changes = json['changes'];
+ final documentChanges = json['documentChanges']
+ ?.map((item) => item)
+ ?.cast<FileOperation>()
+ ?.toList();
+ return new WorkspaceEdit(changes, documentChanges);
+ }
/// Holds changes to existing resources.
final Map<String, List<TextEdit>> changes;
/// Depending on the client capability
- /// `workspace.workspaceEdit.resourceOperations` document changes are either
- /// an array of `TextDocumentEdit`s to express changes to n different text
- /// documents where each text document edit addresses a specific version of a
- /// text document. Or it can contain above `TextDocumentEdit`s mixed with
- /// create, rename and delete file / folder operations.
+ /// `workspace.workspaceEdit.resourceOperations`
+ /// document changes are either an array of
+ /// `TextDocumentEdit`s to express changes to n
+ /// different text documents where each text
+ /// document edit addresses a specific version
+ /// of a text document. Or it can contain above
+ /// `TextDocumentEdit`s mixed with create,
+ /// rename and delete file / folder operations.
///
- /// Whether a client supports versioned document edits is expressed via
- /// `workspace.workspaceEdit.documentChanges` client capability.
+ /// Whether a client supports versioned document
+ /// edits is expressed via
+ /// `workspace.workspaceEdit.documentChanges`
+ /// client capability.
///
- /// If a client neither supports `documentChanges` nor
- /// `workspace.workspaceEdit.resourceOperations` then only plain `TextEdit`s
- /// using the `changes` property are supported.
+ /// If a client neither supports
+ /// `documentChanges` nor
+ /// `workspace.workspaceEdit.resourceOperations`
+ /// then only plain `TextEdit`s using the
+ /// `changes` property are supported.
final List<FileOperation> documentChanges;
Map<String, dynamic> toJson() {
@@ -3338,15 +6752,38 @@
}
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ const validFieldNames = ['changes', 'documentChanges'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
class WorkspaceFolder {
- WorkspaceFolder(this.uri, this.name);
+ WorkspaceFolder(this.uri, this.name) {
+ if (uri == null) {
+ throw 'uri is required but was not provided';
+ }
+ if (name == null) {
+ throw 'name is required but was not provided';
+ }
+ }
+ factory WorkspaceFolder.fromJson(Map<String, dynamic> json) {
+ final uri = json['uri'];
+ final name = json['name'];
+ return new WorkspaceFolder(uri, name);
+ }
- /// The name of the workspace folder. Defaults to the uri's basename.
+ /// The name of the workspace folder. Defaults
+ /// to the uri's basename.
final String name;
- /// The associated URI for this workspace folder.
+ /// The associated URI for this workspace
+ /// folder.
final String uri;
Map<String, dynamic> toJson() {
@@ -3355,11 +6792,44 @@
__result['name'] = name ?? (throw 'name is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('uri') || !map['uri'] is String) {
+ return false;
+ }
+ if (!map.containsKey('name') || !map['name'] is String) {
+ return false;
+ }
+ const validFieldNames = ['uri', 'name'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// The workspace folder change event.
class WorkspaceFoldersChangeEvent {
- WorkspaceFoldersChangeEvent(this.added, this.removed);
+ WorkspaceFoldersChangeEvent(this.added, this.removed) {
+ if (added == null) {
+ throw 'added is required but was not provided';
+ }
+ if (removed == null) {
+ throw 'removed is required but was not provided';
+ }
+ }
+ factory WorkspaceFoldersChangeEvent.fromJson(Map<String, dynamic> json) {
+ final added = json['added']
+ ?.map((item) => new WorkspaceFolder.fromJson(item))
+ ?.cast<WorkspaceFolder>()
+ ?.toList();
+ final removed = json['removed']
+ ?.map((item) => new WorkspaceFolder.fromJson(item))
+ ?.cast<WorkspaceFolder>()
+ ?.toList();
+ return new WorkspaceFoldersChangeEvent(added, removed);
+ }
/// The array of added workspace folders
final List<WorkspaceFolder> added;
@@ -3374,11 +6844,42 @@
removed ?? (throw 'removed is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('added') ||
+ !(map['added'] is List &&
+ (map['added'].length == 0 ||
+ map['added']
+ .every((item) => WorkspaceFolder.canParse(item))))) {
+ return false;
+ }
+ if (!map.containsKey('removed') ||
+ !(map['removed'] is List &&
+ (map['removed'].length == 0 ||
+ map['removed']
+ .every((item) => WorkspaceFolder.canParse(item))))) {
+ return false;
+ }
+ const validFieldNames = ['added', 'removed'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
/// The parameters of a Workspace Symbol Request.
class WorkspaceSymbolParams {
- WorkspaceSymbolParams(this.query);
+ WorkspaceSymbolParams(this.query) {
+ if (query == null) {
+ throw 'query is required but was not provided';
+ }
+ }
+ factory WorkspaceSymbolParams.fromJson(Map<String, dynamic> json) {
+ final query = json['query'];
+ return new WorkspaceSymbolParams(query);
+ }
/// A non-empty query string
final String query;
@@ -3388,4 +6889,16 @@
__result['query'] = query ?? (throw 'query is required but was not set');
return __result;
}
+
+ static bool canParse(Object obj) {
+ if (!obj is Map<String, dynamic>) {
+ return false;
+ }
+ final map = obj as Map<String, dynamic>;
+ if (!map.containsKey('query') || !map['query'] is String) {
+ return false;
+ }
+ const validFieldNames = ['query'];
+ return map.keys.every((k) => validFieldNames.contains(k));
+ }
}
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
index 6dd189a..b6f1909 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
@@ -16,11 +16,19 @@
: _t1 = null,
_which = 2;
+ @override
+ get hashCode => map((t) => t.hashCode, (t) => t.hashCode);
+
+ bool operator ==(o) => o is Either2<T1, T2> && o._t1 == _t1 && o._t2 == _t2;
+
T map<T>(T Function(T1) f1, T Function(T2) f2) {
return _which == 1 ? f1(_t1) : f2(_t2);
}
Object toJson() => map(id, id);
+
+ /// Checks whether the value of the union equals the supplied value.
+ bool valueEquals(o) => map((t) => t == o, (t) => t == o);
}
class Either3<T1, T2, T3> {
@@ -42,6 +50,12 @@
_t2 = null,
_which = 3;
+ @override
+ get hashCode => map((t) => t.hashCode, (t) => t.hashCode, (t) => t.hashCode);
+
+ bool operator ==(o) =>
+ o is Either3<T1, T2, T3> && o._t1 == _t1 && o._t2 == _t2 && o._t3 == _t3;
+
T map<T>(T Function(T1) f1, T Function(T2) f2, T Function(T3) f3) {
switch (_which) {
case 1:
@@ -56,6 +70,9 @@
}
Object toJson() => map(id, id, id);
+
+ /// Checks whether the value of the union equals the supplied value.
+ bool valueEquals(o) => map((t) => t == o, (t) => t == o, (t) => t == o);
}
class Either4<T1, T2, T3, T4> {
@@ -86,6 +103,17 @@
_t3 = null,
_which = 4;
+ @override
+ get hashCode => map((t) => t.hashCode, (t) => t.hashCode, (t) => t.hashCode,
+ (t) => t.hashCode);
+
+ bool operator ==(o) =>
+ o is Either4<T1, T2, T3, T4> &&
+ o._t1 == _t1 &&
+ o._t2 == _t2 &&
+ o._t3 == _t3 &&
+ o._t4 == _t4;
+
T map<T>(T Function(T1) f1, T Function(T2) f2, T Function(T3) f3,
T Function(T4) f4) {
switch (_which) {
@@ -103,6 +131,10 @@
}
Object toJson() => map(id, id, id, id);
+
+ /// Checks whether the value of the union equals the supplied value.
+ bool valueEquals(o) =>
+ map((t) => t == o, (t) => t == o, (t) => t == o, (t) => t == o);
}
class FileOperation {}
diff --git a/pkg/analysis_server/test/tool/lsp_spec/json_test.dart b/pkg/analysis_server/test/tool/lsp_spec/json_test.dart
index 70be648..646d49a 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/json_test.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/json_test.dart
@@ -17,7 +17,7 @@
expect(json.encode(_string.toJson()), equals('"Test"'));
});
- test('returns correct output for types unions', () {
+ test('returns correct output for union types', () {
final message = new RequestMessage(new Either2.t1(1), "test", "test");
String output = json.encode(message.toJson());
expect(output, equals('{"id":1,"method":"test","jsonrpc":"test"}'));
@@ -63,7 +63,7 @@
expect(output, equals(expected));
});
- test('enums serialise to their underlying values', () {
+ test('serialises enums to their underlying values', () {
final foldingRange =
new FoldingRange(1, 2, 3, 4, FoldingRangeKind.Comment);
final output = json.encode(foldingRange.toJson());
@@ -78,4 +78,54 @@
expect(output, equals(expected));
});
});
+
+ group('fromJson', () {
+ test('parses JSON for types with unions (left side)', () {
+ final input = '{"id":1,"method":"test","jsonrpc":"test"}';
+ final message = new RequestMessage.fromJson(jsonDecode(input));
+ expect(message.id, equals(new Either2<num, String>.t1(1)));
+ expect(message.id.valueEquals(1), isTrue);
+ expect(message.jsonrpc, "test");
+ expect(message.method, "test");
+ });
+
+ test('parses JSON for types with unions (right side)', () {
+ final input = '{"id":"one","method":"test","jsonrpc":"test"}';
+ final message = new RequestMessage.fromJson(jsonDecode(input));
+ expect(message.id, equals(new Either2<num, String>.t2("one")));
+ expect(message.id.valueEquals("one"), isTrue);
+ expect(message.jsonrpc, "test");
+ expect(message.method, "test");
+ });
+ });
+
+ test('objects with lists and enums can round-trip through to json and back',
+ () {
+ final obj = new ClientCapabilities(
+ new WorkspaceClientCapabilities(
+ true,
+ false,
+ [ResourceOperationKind.Create, ResourceOperationKind.Delete],
+ FailureHandlingKind.Undo),
+ new TextDocumentClientCapabilities(true, false, true, false),
+ null);
+ final String json = jsonEncode(obj);
+ final restoredObj = new ClientCapabilities.fromJson(jsonDecode(json));
+
+ expect(restoredObj.workspace.applyEdit, equals(obj.workspace.applyEdit));
+ expect(restoredObj.workspace.documentChanges,
+ equals(obj.workspace.documentChanges));
+ expect(restoredObj.workspace.resourceOperations,
+ equals(obj.workspace.resourceOperations));
+ expect(restoredObj.workspace.failureHandling,
+ equals(obj.workspace.failureHandling));
+ expect(restoredObj.textDocument.didSave, equals(obj.textDocument.didSave));
+ expect(restoredObj.textDocument.dynamicRegistration,
+ equals(obj.textDocument.dynamicRegistration));
+ expect(
+ restoredObj.textDocument.willSave, equals(obj.textDocument.willSave));
+ expect(restoredObj.textDocument.willSaveWaitUntil,
+ equals(obj.textDocument.willSaveWaitUntil));
+ expect(restoredObj.experimental, equals(obj.experimental));
+ });
}
diff --git a/pkg/analysis_server/test/tool/lsp_spec/typescript_to_dart_test.dart b/pkg/analysis_server/test/tool/lsp_spec/typescript_to_dart_test.dart
deleted file mode 100644
index 9cd5290..0000000
--- a/pkg/analysis_server/test/tool/lsp_spec/typescript_to_dart_test.dart
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2018, 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.
-
-import 'package:test/test.dart';
-
-import '../../../tool/lsp_spec/codegen_dart.dart';
-import '../../../tool/lsp_spec/typescript.dart';
-
-main() {
- group('typescript converts to dart', () {
- void convertAndCompare(String input, String expectedOutput) {
- final String output = generateDartForTypes(extractTypes(input));
- expect(output.trim(), equals(expectedOutput.trim()));
- }
-
- // TODO(dantup): These types are missing constructors, toJson, fromJson, etc.
-
- test('for an interface', () {
- final String input = '''
-/**
- * Some options.
- */
-export interface SomeOptions {
- /**
- * Options used by something.
- */
- options?: OptionKind[];
-}
- ''';
- final String expectedOutput = '''
-/// Some options.
-class SomeOptions {
- SomeOptions(this.options);
-
- /// Options used by something.
- final List<OptionKind> options;
-}
- ''';
- convertAndCompare(input, expectedOutput);
- });
-
- test('uses aliases types in place of aliases', () {
- final String input = '''
-type DocumentUri = string;
-
-export interface SomeDocumentThing {
- uris: DocumentUri[];
-}
- ''';
- final String expectedOutput = '''
-class SomeDocumentThing {
- SomeDocumentThing(this.uris);
-
- final List<String /*DocumentUri*/ > uris;
-}
- ''';
- convertAndCompare(input, expectedOutput);
- });
-
- test('outputs references in comments in the correct format', () {
- final String input = '''
-export interface One {
-}
-
-/**
- * This may refer to [a one](#One) or just [One](#One).
- */
-export interface Two {
-}
- ''';
- final String expectedOutput = '''
-class One {}
-
-/// This may refer to a one ([One]) or just [One].
-class Two {}
- ''';
- convertAndCompare(input, expectedOutput);
- });
- // Skip these tests while toJson methods/etc. are in progress and the generated
- // code changes frequently.
- // TODO(dantup): Re-enable these.
- }, skip: true);
-}
diff --git a/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart b/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
index 3018259..065a31b 100644
--- a/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
+++ b/pkg/analysis_server/tool/lsp_spec/codegen_dart.dart
@@ -8,6 +8,7 @@
final formatter = new DartFormatter();
Map<String, Interface> _interfaces = {};
+Map<String, Namespace> _namespaces = {};
Map<String, TypeAlias> _typeAliases = {};
String generateDartForTypes(List<ApiItem> types) {
@@ -18,6 +19,9 @@
types
.whereType<Interface>()
.forEach((interface) => _interfaces[interface.name] = interface);
+ types
+ .whereType<Namespace>()
+ .forEach((namespace) => _namespaces[namespace.name] = namespace);
final buffer = new IndentableStringBuffer();
_getSorted(types).forEach((t) => _writeType(buffer, t));
final formattedCode = _formatCode(buffer.toString());
@@ -48,6 +52,10 @@
.toList();
}
+String _getListType(String type) {
+ return type.substring('List<'.length, type.length - 1);
+}
+
/// Returns a copy of the list sorted by name.
List<ApiItem> _getSorted(List<ApiItem> items) {
final sortedList = items.toList();
@@ -55,6 +63,31 @@
return sortedList;
}
+List<String> _getUnionTypes(String type) {
+ return type
+ .substring('EitherX<'.length, type.length - 1)
+ .split(',')
+ .map((s) => s.trim())
+ .toList();
+}
+
+bool _isList(String type) {
+ return type.startsWith('List<') && type.endsWith('>');
+}
+
+bool _isLiteral(String type) {
+ const literals = ['num', 'String', 'bool'];
+ return literals.contains(type);
+}
+
+bool _isSpecType(String type) {
+ return _interfaces.containsKey(type) || _namespaces.containsKey(type);
+}
+
+bool _isUnion(String type) {
+ return type.startsWith('Either') && type.endsWith('>');
+}
+
/// Maps reserved words and identifiers that cause issues in field names.
String _makeValidIdentifier(String identifier) {
// The SymbolKind class has uses these names which cause issues for code that
@@ -133,6 +166,42 @@
}
}
+void _writeCanParseMethod(IndentableStringBuffer buffer, Interface interface) {
+ buffer
+ ..writeIndentedln('static bool canParse(Object obj) {')
+ ..indent()
+ ..writeIndentedln('if (!obj is Map<String, dynamic>) {')
+ ..indent()
+ ..writeIndentedln('return false;')
+ ..outdent()
+ ..writeIndentedln('}')
+ ..writeIndentedln('final map = obj as Map<String, dynamic>;');
+ // In order to consider this valid for parsing, all fields that may not be
+ // undefined must be present and also type check for the correct type.
+ // If these pass, there must also be no fields that are not defined for this
+ // type.
+ final allFields = _getAllFields(interface);
+ final requiredFields = allFields.where((f) => !f.allowsUndefined);
+ for (var field in requiredFields) {
+ buffer.writeIndented("if (!map.containsKey('${field.name}') || !");
+ _writeTypeCheckCondition(
+ buffer, "map['${field.name}']", _mapType(field.types));
+ buffer
+ ..writeln(') {')
+ ..indent()
+ ..writeIndentedln('return false;')
+ ..outdent()
+ ..writeIndentedln('}');
+ }
+ final fieldNames = allFields.map((f) => f.name).join("', '");
+ buffer.writeIndentedln("const validFieldNames = ['$fieldNames'];");
+ buffer
+ ..writeIndentedln(
+ 'return map.keys.every((k) => validFieldNames.contains(k));')
+ ..outdent()
+ ..writeIndentedln('}');
+}
+
void _writeConst(IndentableStringBuffer buffer, Const cons) {
_writeDocCommentsAndAnnotations(buffer, cons);
buffer.writeIndentedln('static const ${cons.name} = ${cons.value};');
@@ -146,7 +215,28 @@
buffer
..writeIndented('${interface.name}(')
..write(allFields.map((field) => 'this.${field.name}').join(', '))
- ..writeln(');');
+ ..write(')');
+ final fieldsWithValidation =
+ allFields.where((f) => !f.allowsNull && !f.allowsUndefined).toList();
+ if (fieldsWithValidation.isNotEmpty) {
+ buffer
+ ..writeIndentedln(' {')
+ ..indent();
+ for (var field in fieldsWithValidation) {
+ buffer
+ ..writeIndentedln('if (${field.name} == null) {')
+ ..indent()
+ ..writeIndentedln(
+ "throw '${field.name} is required but was not provided';")
+ ..outdent()
+ ..writeIndentedln('}');
+ }
+ buffer
+ ..outdent()
+ ..writeIndentedln('}');
+ } else {
+ buffer.writeln(';');
+ }
}
void _writeDocCommentsAndAnnotations(
@@ -158,7 +248,7 @@
comment = _rewriteCommentReference(comment);
Iterable<String> lines = comment.split('\n');
// Wrap at 80 - 4 ('/// ') - indent characters.
- lines = _wrapLines(lines, 80 - 4 - buffer.totalIndent);
+ lines = _wrapLines(lines, (80 - 4 - buffer.totalIndent).clamp(0, 80));
lines.forEach((l) => buffer.writeIndentedln('/// $l'.trim()));
if (item.isDeprecated) {
buffer.writeIndentedln('@core.deprecated');
@@ -171,9 +261,25 @@
..writeln('class ${namespace.name} {')
..indent()
..writeIndentedln('const ${namespace.name}._(this._value);')
+ ..writeIndentedln('const ${namespace.name}.fromJson(this._value);')
..writeln()
..writeIndentedln('final Object _value;')
- ..writeln();
+ ..writeln()
+ ..writeIndentedln('static bool canParse(Object obj) {')
+ ..indent()
+ ..writeIndentedln('switch (obj) {')
+ ..indent();
+ namespace.members.whereType<Const>().forEach((cons) {
+ buffer..writeIndentedln('case ${cons.value}:');
+ });
+ buffer
+ ..indent()
+ ..writeIndentedln('return true;')
+ ..outdent()
+ ..writeIndentedln('}')
+ ..writeIndentedln('return false;')
+ ..outdent()
+ ..writeIndentedln('}');
namespace.members.whereType<Const>().forEach((cons) {
_writeDocCommentsAndAnnotations(buffer, cons);
buffer
@@ -203,6 +309,70 @@
..writeln(' ${field.name};');
}
+void _writeFromJsonCode(
+ IndentableStringBuffer buffer, List<String> types, String valueCode) {
+ final type = _mapType(types);
+ if (_isLiteral(type)) {
+ buffer.write("$valueCode");
+ } else if (_isSpecType(type)) {
+ // Our own types have fromJson() constructors we can call.
+ buffer.write("new $type.fromJson($valueCode)");
+ } else if (_isList(type)) {
+ // Lists need to be mapped so we can recursively call (they may need fromJson).
+ buffer.write("$valueCode?.map((item) => ");
+ final listType = _getListType(type);
+ _writeFromJsonCode(buffer, [listType], 'item');
+ buffer.write(')?.cast<$listType>()?.toList()');
+ } else if (_isUnion(type)) {
+ _writeFromJsonCodeForUnion(buffer, types, valueCode);
+ } else {
+ buffer.write("$valueCode");
+ }
+}
+
+void _writeFromJsonCodeForUnion(
+ IndentableStringBuffer buffer, List<String> types, String valueCode) {
+ final unionTypeName = _mapType(types);
+ // Write a check against each type, eg.:
+ // x is y ? new Either.tx(x) : (...)
+ for (var i = 0; i < types.length; i++) {
+ final dartType = _mapType([types[i]]);
+
+ _writeTypeCheckCondition(buffer, valueCode, dartType);
+ buffer.write(' ? new $unionTypeName.t${i + 1}(');
+ _writeFromJsonCode(buffer, [dartType], valueCode); // Call recursively!
+ buffer.write(') : (');
+ }
+ // Fill the final parens with a throw because if we fell through all of the
+ // cases then the value we had didn't match any of the types in the union.
+ buffer
+ .write("throw '''\${$valueCode} was not one of (${types.join(', ')})'''");
+ buffer.write(')' * types.length);
+}
+
+void _writeFromJsonConstructor(
+ IndentableStringBuffer buffer, Interface interface) {
+ final allFields = _getAllFields(interface);
+ if (allFields.isEmpty) {
+ return;
+ }
+ buffer
+ ..writeIndentedln(
+ 'factory ${interface.name}.fromJson(Map<String, dynamic> json) {')
+ ..indent();
+ for (final field in allFields) {
+ buffer.writeIndented('final ${field.name} = ');
+ _writeFromJsonCode(buffer, field.types, "json['${field.name}']");
+ buffer.writeln(';');
+ }
+ buffer
+ ..writeIndented('return new ${interface.name}(')
+ ..write(allFields.map((field) => '${field.name}').join(', '))
+ ..writeln(');')
+ ..outdent()
+ ..write('}');
+}
+
void _writeInterface(IndentableStringBuffer buffer, Interface interface) {
_writeDocCommentsAndAnnotations(buffer, interface);
@@ -214,6 +384,7 @@
..writeln('{')
..indent();
_writeConstructor(buffer, interface);
+ _writeFromJsonConstructor(buffer, interface);
// Handle Consts and Fields separately, since we need to include superclass
// Fields.
final consts = interface.members.whereType<Const>().toList();
@@ -224,7 +395,7 @@
_writeMembers(buffer, fields);
buffer.writeln();
_writeToJsonMethod(buffer, interface);
- // TODO(dantup): Generate fromJson()
+ _writeCanParseMethod(buffer, interface);
buffer
..outdent()
..writeIndentedln('}')
@@ -324,6 +495,37 @@
}
}
+void _writeTypeCheckCondition(
+ IndentableStringBuffer buffer, String valueCode, String dartType) {
+ if (dartType == 'dynamic') {
+ buffer.write('true');
+ } else if (_isLiteral(dartType)) {
+ buffer.write('$valueCode is $dartType');
+ } else if (_isSpecType(dartType)) {
+ buffer.write('$dartType.canParse($valueCode)');
+ } else if (_isList(dartType)) {
+ // TODO(dantup): If we're happy to assume we never have two lists in a union
+ // we could simplify this to '$valueCode is List'.
+ buffer.write(
+ '($valueCode is List && ($valueCode.length == 0 || $valueCode.every((item) => ');
+ _writeTypeCheckCondition(buffer, 'item', _getListType(dartType));
+ buffer.write(')))');
+ } else if (_isUnion(dartType)) {
+ // To type check a union, we just recursively check against each of its types.
+ final unionTypes = _getUnionTypes(dartType);
+ buffer.write('(');
+ for (var i = 0; i < unionTypes.length; i++) {
+ if (i != 0) {
+ buffer.write(' || ');
+ }
+ _writeTypeCheckCondition(buffer, valueCode, _mapType([unionTypes[i]]));
+ }
+ buffer.write(')');
+ } else {
+ throw 'Unable to type check $valueCode against $dartType';
+ }
+}
+
class IndentableStringBuffer extends StringBuffer {
int _indentLevel = 0;
int _indentSpaces = 2;