Skip to content
This repository was archived by the owner on Mar 18, 2021. It is now read-only.

Jc/documentation #27

Merged
merged 7 commits into from
Jan 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/auth/auth_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ class AuthController<ResourceOwner extends Authenticatable, TokenType extends To
acceptedContentTypes = [new ContentType("application", "x-www-form-urlencoded")];
}

/// Creates or refreshes an authentication token.
///
/// Authorization header must contain Basic authorization scheme where username is Client ID and password is Client Secret,
/// e.g. Authorization: Basic base64(ClientID:ClientSecret)
/// Content-Type must be application/x-www-form-urlencoded. (Query string in the body, e.g. username=bob&password=password)
/// Values must be URL percent encoded by client.
/// When grant_type is 'password', there must be username and password values.
/// When grant_type is 'refresh', there must be a refresh_token value.
@httpPost
Future<Response> create({String grant_type, String username, String password, String refresh_token}) async {
var authorizationHeader = request.innerRequest.headers[HttpHeaders.AUTHORIZATION]?.first;
Expand Down
4 changes: 2 additions & 2 deletions lib/auth/authenticator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ class Authenticator extends RequestHandler {
}


List<APIDocumentItem> document() {
List<APIDocumentItem> items = nextHandler.document();
List<APIDocumentItem> document(PackagePathResolver resolver) {
List<APIDocumentItem> items = nextHandler.document(resolver);

items.forEach((i) {
if (strategy == AuthenticationStrategy.Client) {
Expand Down
43 changes: 38 additions & 5 deletions lib/base/documentable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class APIDocument {
}

abstract class APIDocumentable {
List<APIDocumentItem> document();
List<APIDocumentItem> document(PackagePathResolver resolver);
}

enum APISecurityType {
Expand All @@ -89,10 +89,9 @@ class APISecurityItem {
m["description"] = description;

switch(type) {
case APISecurityType.basic:
{
case APISecurityType.basic: {
m["type"] = "basic";
} break;
} break;
case APISecurityType.oauth2: {
m["type"] = "oauth2";
if (flow != null) {
Expand All @@ -113,14 +112,15 @@ class APIDocumentItem {
String path;
String method;
String securityItemName;
String description;
List<String> acceptedContentTypes;
List<APIParameter> pathParameters;
List<APIParameter> queryParameters;
List<String> responseFormats;

Map<String, dynamic> asMap() {
Map<String, dynamic> i = {};
i["description"] = "Description";
i["description"] = description ?? "";
i["produces"] = responseFormats;

var combined = [];
Expand Down Expand Up @@ -177,8 +177,41 @@ class APIParameter {
case "String" : m["type"] = "string"; break;
case "bool" : m["type"] = "bool"; break;
case "double" : m["type"] = "number"; break;
default: m["type"] = "string";
}

return m;
}
}

class PackagePathResolver {
PackagePathResolver(String packageMapPath) {
var contents = new File(packageMapPath).readAsStringSync();
var lines = contents
.split("\n")
.where((l) => !l.startsWith("#") && l.indexOf(":") != -1)
.map((l) {
var firstColonIdx = l.indexOf(":");
var packageName = l.substring(0, firstColonIdx);
var packagePath = l.substring(firstColonIdx + 1, l.length).replaceFirst(r"file://", "");
return [packageName, packagePath];
});
_map = new Map.fromIterable(lines, key: (k) => k.first, value: (v) => v.last);
}

Map<String, String> _map;

String resolve(Uri uri) {
if (uri.scheme == "package") {
var firstElement = uri.pathSegments.first;
var packagePath = _map[firstElement];
if (packagePath == null) {
throw new Exception("Package $firstElement could not be resolved.");
}

var remainingPath = uri.pathSegments.sublist(1).join("/");
return "$packagePath$remainingPath";
}
return uri.path;
}
}
27 changes: 26 additions & 1 deletion lib/base/http_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -262,15 +262,39 @@ abstract class HttpController extends RequestHandler {
}

@override
List<APIDocumentItem> document() {
List<APIDocumentItem> document(PackagePathResolver resolver) {
var handlerMethodMirrors = reflect(this).type.declarations.values
.where((dm) => dm is MethodMirror)
.where((mm) {
return mm.metadata.firstWhere((im) => im.reflectee is HttpMethod, orElse: () => null) != null;
});

var reflectedType = reflect(this).type;
var uri = reflectedType.location.sourceUri;
var fileUnit = parseDartFile(resolver.resolve(uri));

var classUnit = fileUnit.declarations
.where((u) => u is ClassDeclaration)
.firstWhere((ClassDeclaration u) => u.name.token.lexeme == MirrorSystem.getName(reflectedType.simpleName));

Map<String, MethodDeclaration> methodMap = {};
classUnit.childEntities.forEach((child) {
if (child is MethodDeclaration) {
MethodDeclaration c = child;
methodMap[c.name.token.lexeme] = child;
}
});

return handlerMethodMirrors.map((MethodMirror mm) {
var i = new APIDocumentItem();

var matchingMethodDeclaration = methodMap[MirrorSystem.getName(mm.simpleName)];
if (matchingMethodDeclaration != null) {
var comment = matchingMethodDeclaration.documentationComment;
var tokens = comment?.tokens ?? [];
i.description = tokens.map((t) => t.lexeme.trimLeft().substring(3).trim()).join("\n");
}

var httpMethod = mm.metadata.firstWhere((im) => im.reflectee is HttpMethod).reflectee;

i.method = httpMethod.method;
Expand Down Expand Up @@ -308,6 +332,7 @@ abstract class HttpController extends RequestHandler {

i.acceptedContentTypes = acceptedContentTypes.map((ct) => "${ct.primaryType}/${ct.subType}").toList();
i.responseFormats = ["${responseContentType.primaryType}/${responseContentType.subType}"];

return i;
}).toList();
}
Expand Down
4 changes: 2 additions & 2 deletions lib/base/pipeline.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ abstract class ApplicationPipeline extends RequestHandler {
}

@override
List<APIDocumentItem> document() {
return initialHandler().document();
List<APIDocumentItem> document(PackagePathResolver resolver) {
return initialHandler().document(resolver);
}
}
8 changes: 4 additions & 4 deletions lib/base/request_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ class RequestHandler implements APIDocumentable {
return req;
}

List<APIDocumentItem> document() {
List<APIDocumentItem> document(PackagePathResolver resolver) {
if (nextHandler != null) {
return nextHandler.document();
return nextHandler.document(resolver);
}

return [];
Expand All @@ -122,8 +122,8 @@ class RequestHandlerGenerator<T extends RequestHandler> extends RequestHandler {
}

@override
List<APIDocumentItem> document() {
return instantiate().document();
List<APIDocumentItem> document(PackagePathResolver resolver) {
return instantiate().document(resolver);
}

}
4 changes: 2 additions & 2 deletions lib/base/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ class Router extends RequestHandler {
}

@override
List<APIDocumentItem> document() {
List<APIDocumentItem> document(PackagePathResolver resolver) {
List<APIDocumentItem> items = [];

for (var route in _routes) {
var routeItems = route.handler.document();
var routeItems = route.handler.document(resolver);

items.addAll(routeItems.map((i) {
i.path = (basePath ?? "") + route.pattern.documentedPathWithVariables(i.pathParameters);
Expand Down
24 changes: 13 additions & 11 deletions lib/db/postgresql/postgresl_query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,23 @@ class _PostgresqlQuery {
return;
}

var relatedValue = (value as Model).dynamicBacking[column.relationship.destinationModelKey];
if (value != null) {
var relatedValue = (value as Model).dynamicBacking[column.relationship.destinationModelKey];

if (relatedValue == null) {
var thisType = MirrorSystem.getName(reflect(valueObject).type.simpleName);
if (relatedValue == null) {
var thisType = MirrorSystem.getName(reflect(valueObject).type.simpleName);

var relatedType = MirrorSystem.getName(reflectType(column.relationship.destinationType).simpleName);
var relatedType = MirrorSystem.getName(reflectType(column.relationship.destinationType).simpleName);

throw new QueryException(
500,
"Query object of type ${thisType} contains embedded object of type ${relatedType},"
"but embedded object does not contain foreign model key ${column.relationship.destinationModelKey}",
-1);
}
throw new QueryException(500, "Query object of type ${thisType} contains embedded object of type ${relatedType},"
"but embedded object does not contain foreign model key ${column.relationship.destinationModelKey}",
-1);
}

m[column.name] = relatedValue;
m[column.name] = relatedValue;
} else {
m[column.name] = null;
}
} else {
m[column.name] = value;
}
Expand Down
1 change: 1 addition & 0 deletions lib/monadart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:http/http.dart' as http;
import 'package:logging/logging.dart';
import 'package:postgresql/postgresql.dart';
import 'package:matcher/matcher.dart';
import 'package:analyzer/analyzer.dart';

export 'package:http_server/http_server.dart';
export 'package:logging/logging.dart';
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ dependencies:
crypto: any
http: any
logging: any
analyzer: any
postgresql: '0.3.2'

dev_dependencies:
Expand Down
77 changes: 77 additions & 0 deletions test/base/document_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import 'package:test/test.dart';
import 'package:monadart/monadart.dart';
import 'dart:mirrors';
import 'dart:async';
import 'package:analyzer/analyzer.dart';
import 'dart:convert';
import 'dart:io';

main() {
test("Package resolver", () {
String homeDir = Platform.environment['HOME'] ?? Platform.environment['USERPROFILE'];
var p = new PackagePathResolver(new File(".packages").path);
var resolvedPath = p.resolve(new Uri(scheme: "package", path: "analyzer/file_system/file_system.dart"));

expect(resolvedPath.endsWith("file_system/file_system.dart"), true);
expect(resolvedPath.startsWith("$homeDir/.pub-cache/hosted/pub.dartlang.org"), true);
});

test("Documentation test", () {
var t = new TController();
// print("${t.document().asMap()}");


});

test("Tests", () {
// ApplicationPipeline pipeline = new TPipeline({});
// pipeline.addRoutes();
//
// var docs = pipeline.document();
// var document = new APIDocument()
// ..items = docs;

});

}

class TPipeline extends ApplicationPipeline {
TPipeline(Map opts) : super(opts);

void addRoutes() {
router.route("/t").then(new RequestHandlerGenerator<TController>());
}
}

///
/// Documentation
///
class TController extends HttpController {
/// ABCD
/// EFGH
/// IJKL
@httpGet getAll() async {
return new Response.ok("");
}
/// ABCD
@httpPut putOne(int id) async {
return new Response.ok("");
}
@httpGet getOne(int id) async {
return new Response.ok("");
}

/// MNOP
/// QRST

@httpGet getTwo(int id, int notID) async {
return new Response.ok("");
}
/// EFGH
/// IJKL
@httpPost

Future<Response> createOne() async {
return new Response.ok("");
}
}
Loading