Skip to content

Commit

Permalink
merge: 'parse-links' into 'main'
Browse files Browse the repository at this point in the history
feat: let TD parse links field

See merge request namib-master/libraries/dart_wot!27
  • Loading branch information
JKRhb committed Jan 22, 2022
2 parents 797ae26 + 8ddadfb commit 8a648bc
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 1 deletion.
95 changes: 95 additions & 0 deletions lib/src/definitions/link.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2022 The NAMIB Project Developers. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// SPDX-License-Identifier: BSD-3-Clause

/// Represents an element of the `links` array in a Thing Description.
///
/// A link can be viewed as a statement of the form "link context has a relation
/// type resource at link target", where the optional target attributes may
/// further describe the resource.
class Link {
/// Target IRI of a link or submission target of a form.
late final Uri href;

/// Target attribute providing a hint indicating what the media type (see RFC
/// 2046) of the result of dereferencing the link should be.
String? type;

/// A link relation type identifies the semantics of a link.
String? rel;

/// Overrides the link context (by default the Thing itself identified by its
/// id) with the given URI or IRI.
Uri? anchor;

/// Target attribute that specifies one or more sizes for a referenced icon.
///
/// Only applicable for relation type "icon". The value pattern follows
/// {Height}x{Width} (e.g., "16x16", "16x16 32x32").
String? sizes;

final List<String> _parsedJsonFields = [];

/// Additional fields collected during the parsing of a JSON object.
final Map<String, dynamic> additionalFields = <String, dynamic>{};

/// Constructor.
Link(
String href, {
this.type,
this.rel,
String? anchor,
this.sizes,
Map<String, dynamic>? additionalFields,
}) : href = Uri.parse(href),
anchor = anchor != null ? Uri.parse(anchor) : null {
if (additionalFields != null) {
this.additionalFields.addAll(additionalFields);
}
}

/// Creates a new [Link] from a [json] object.
Link.fromJson(Map<String, dynamic> json) {
// TODO(JKRhb): Check if this can be refactored
if (json["href"] is String) {
_parsedJsonFields.add("href");
final hrefString = json["href"] as String;
href = Uri.parse(hrefString);
} else {
// [href] *must* be initialized.
throw ArgumentError("'href' field must exist as a string.", "formJson");
}

if (json["type"] is String) {
_parsedJsonFields.add("type");
type = json["type"] as String;
}

if (json["rel"] is String) {
_parsedJsonFields.add("rel");
rel = json["rel"] as String;
}

if (json["anchor"] is String) {
_parsedJsonFields.add("anchor");
anchor = Uri.parse(json["anchor"] as String);
}

if (json["sizes"] is String) {
_parsedJsonFields.add("sizes");
sizes = json["sizes"] as String;
}

_addAdditionalFields(json);
}

void _addAdditionalFields(Map<String, dynamic> formJson) {
for (final entry in formJson.entries) {
if (!_parsedJsonFields.contains(entry.key)) {
additionalFields[entry.key] = entry.value;
}
}
}
}
16 changes: 16 additions & 0 deletions lib/src/definitions/thing_description.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'context_entry.dart';
import 'interaction_affordances/action.dart';
import 'interaction_affordances/event.dart';
import 'interaction_affordances/property.dart';
import 'link.dart';
import 'security_scheme.dart';
import 'thing_model.dart';

Expand Down Expand Up @@ -47,6 +48,9 @@ class ThingDescription {
/// A [Map] of [Event] Affordances.
Map<String, Event> events = {};

/// A [List] of [Link]s.
final List<Link> links = [];

/// The [base] address of this [ThingDescription]. Might be `null`.
String? base;

Expand Down Expand Up @@ -116,6 +120,10 @@ class ThingDescription {
if (securityDefinitions is Map<String, dynamic>) {
_parseSecurityDefinitions(securityDefinitions);
}
final dynamic links = json["links"];
if (links is List<dynamic>) {
_parseLinks(links);
}
}

// TODO(JKRhb): Refactor
Expand Down Expand Up @@ -167,6 +175,14 @@ class ThingDescription {
ThingDescription.fromThingModel(ThingModel thingModel)
: rawThingModel = thingModel;

void _parseLinks(List<dynamic> json) {
for (final link in json) {
if (link is Map<String, dynamic>) {
links.add(Link.fromJson(link));
}
}
}

void _parseProperties(Map<String, dynamic> json) {
for (final property in json.entries) {
if (property.value is Map<String, dynamic>) {
Expand Down
41 changes: 40 additions & 1 deletion test/dart_wot_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// SPDX-License-Identifier: BSD-3-Clause

import 'package:dart_wot/dart_wot.dart';
import 'package:dart_wot/src/definitions/link.dart';
import 'package:test/test.dart';

// TODO(JKRhb): Add proper tests
Expand Down Expand Up @@ -38,7 +39,17 @@ void main() {
}
]
}
}
},
"links": [
{
"href": "https://example.org",
"rel": "test",
"anchor": "https://example.org",
"type": "test",
"sizes": "42",
"test": "test"
}
]
}
''';
final parsedTd = ThingDescription(thingDescriptionJson);
Expand All @@ -52,6 +63,34 @@ void main() {
expect(firstContextEntry.value, "http://www.w3.org/ns/td");
expect(secondContextEntry.key, "@language");
expect(secondContextEntry.value, "de");

final parsedLink = parsedTd.links[0];
expect(parsedLink.href, Uri.parse("https://example.org"));
expect(parsedLink.rel, "test");
expect(parsedLink.anchor, Uri.parse("https://example.org"));
expect(parsedLink.type, "test");
expect(parsedLink.sizes, "42");
expect(parsedLink.additionalFields["test"], "test");
});

test('Link Tests', () {
final link = Link("https://example.org",
type: "test",
rel: "test",
anchor: "https://example.org",
sizes: "42",
additionalFields: <String, dynamic>{"test": "test"});
expect(link.href, Uri.parse("https://example.org"));
expect(link.rel, "test");
expect(link.anchor, Uri.parse("https://example.org"));
expect(link.type, "test");
expect(link.sizes, "42");
expect(link.additionalFields["test"], "test");

final link2 = Link("https://example.org");
expect(link2.href, Uri.parse("https://example.org"));
expect(link2.anchor, null);
expect(link2.additionalFields, <String, dynamic>{});
});
});
}

0 comments on commit 8a648bc

Please sign in to comment.