import 'dart:collection'; class Embeddable { static const TYPE_KEY = '_type'; static const INLINE_KEY = '_inline'; final String type; final bool inline; final Map _data; Embeddable(this.type, this.inline, Map data) : assert(type != null), assert(inline != null), assert(!data.containsKey(TYPE_KEY)), assert(!data.containsKey(INLINE_KEY)), _data = Map.from(data); Map get data => UnmodifiableMapView(_data); Map toJson() { Map m = Map.from(_data); m[TYPE_KEY] = type; m[INLINE_KEY] = inline; return m; } static Embeddable fromJson(Map json) { String type = json[TYPE_KEY] as String; bool inline = json[INLINE_KEY] as bool; Map data = Map.from(json); data.remove(TYPE_KEY); data.remove(INLINE_KEY); if (inline) { return Span(type, data: data); } return BlockEmbed(type, data: data); } @override bool operator ==(Object other) => identical(this, other) || other is Embeddable && runtimeType == other.runtimeType && type == other.type && inline == other.inline && _data == other._data; @override int get hashCode => type.hashCode ^ inline.hashCode ^ _data.hashCode; } class Span extends Embeddable { Span( String type, { Map data = const {}, }) : super(type, true, data); } class BlockEmbed extends Embeddable { BlockEmbed( String type, { Map data = const {}, }) : super(type, false, data); }