8000 Use flamingo for Dart by kikuchy · Pull Request #1 · kikuchy/lantern · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Use flamingo for Dart #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Dec 9, 2019
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 0.0.3

- Breaking change
- Now generated Dart codes depend on [flamingo](https://pub.dev/packages/flamingo)
- Lantern generates classes for flamingo's Document and Model.
- Generated files are separated into each collection.
- Supports `enum{}` and `struct{}`
- `enum{}` will generate enum values.
- `struct{}` will generate Codable/Model classes.

## 0.0.2

- Omit Firestore rule file generation.
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Lantern has code generation toolkit. You can concentrate to using defined data s
It can provide code for ...

* Swift (depends on [Ballcap-iOS](https://github.com/1amageek/Ballcap-iOS))
* Dart
* Dart (depends on [flamingo](https://pub.dev/packages/flamingo))
* Security rule file for Firestore

## Install
Expand Down Expand Up @@ -91,7 +91,9 @@ And have fields and `collection`s in body.
map history
timestamp birthday
geopoint lastUsedFrom
enum {free, purchased} memberRank
reference<DocumentName> relatedDocument
struct<DocumentName> embeddedDocument
```

|Lantern Type|Firestore Type|Swift Type|Dart type|
Expand All @@ -103,8 +105,10 @@ And have fields and `collection`s in body.
|`url`|`string`|`URL`|`Uri`|
|`array<T>`|`array`|`[T]`|`List<T>`|
|`map`|`map`|`[String : Any]`|`Map<String, dynamic>`|
|`timestamp`|`timestamp`|`Timestamp`|`DateTime`|
|`geopoint`|`geopoint`|`GeoPoint`|`Point`|
|`timestamp`|`timestamp`|`Timestamp`|`Timestamp`|
|`geopoint`|`geopoint`|`GeoPoint`|`GeoPoint`|
|`reference<T>`|`reference`|`Document<T>`|`TDocument` (Document referencing class will be generated)|
|`struct<T>`|`map`|`T` (T should be Codable)|`T` (Document)|
|`file`|`map` (file will be uploaded to Cloud Storage)|`File`|`FireReference`|
|`file`|`map` (file will be uploaded to Cloud Storage)|`File`|`StorageFile`|
|`enum{elements...}`|`string`|`enum` (enum classes will be generated)|`enum`(enum classes will be generated)|
|`struct S {fields...}`|`map`|`S` (Codable class will be generated)|`SModel` (Model class will be generated)|
14 changes: 9 additions & 5 deletions lib/lantern.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import 'package:lantern/src/analyzer.dart';
import 'package:lantern/src/ast.dart';
import 'package:lantern/src/checker.dart';
import 'package:lantern/src/generator/generator.dart';
import 'package:lantern/src/lantern_parser.dart';

List<GeneratedCodeFile> parseLantern(String source) {
final parser = LanternParser();
final parameterChecker = ParameterChecker();
final generators = [
DartCodeGenerator("./"),
SwiftCodeGenerator("./"),
Expand All @@ -13,9 +14,12 @@ List<GeneratedCodeFile> parseLantern(String source) {
// SecurityRulesGenerator("./")
];
final parsed = parser.parse(source).map((schema) {
parameterChecker.check(schema);
return schema;
}).map(
(schema) => generators.map((g) => g.generate(schema)).expand((c) => c));
ParameterChecker().check(schema);
final analyzed = Analyzer().analyze(schema);
TypeChecker().check(analyzed);
// note: Just instead of Tuple
return MapEntry(schema, analyzed);
}).map((pair) =>
generators.map((g) => g.generate(pair.key, pair.value)).expand((c) => c));
return parsed.value.toList();
}
91 changes: 91 additions & 0 deletions lib/src/analyzer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import 'package:collection/collection.dart';
import 'package:lantern/src/ast.dart';

bool Function(dynamic, dynamic) _eq = DeepCollectionEquality().equals;

class AnalyzingResult {
final List<HasValueType> definedEnums = [];
final List<Struct> definedStructs = [];
final List<TypedType> embeddedDocuments = [];
final List<TypedType> referenceToDocument = [];
final List<Collection> definedCollections = [];
final List<Document> definedDocuments = [];
final Map<Document, Collection> parentCollectionOfDocument = {};
final Map<Collection, Document> parentDocumentOfCollection = {};
final Map<Struct, Document> parentDocumentOfStruct = {};

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is AnalyzingResult &&
runtimeType == other.runtimeType &&
_eq(definedEnums, other.definedEnums) &&
_eq(definedStructs, other.definedStructs) &&
_eq(embeddedDocuments, other.embeddedDocuments) &&
_eq(referenceToDocument, other.referenceToDocument) &&
_eq(definedCollections, other.definedCollections) &&
_eq(definedDocuments, other.definedDocuments) &&
_eq(parentCollectionOfDocument, other.parentCollectionOfDocument) &&
_eq(parentDocumentOfCollection, other.parentDocumentOfCollection) &&
_eq(parentDocumentOfStruct, other.parentDocumentOfStruct);

@override
int get hashCode =>
definedEnums.hashCode ^
definedStructs.hashCode ^
embeddedDocuments.hashCode ^
referenceToDocument.hashCode ^
definedCollections.hashCode ^
definedDocuments.hashCode ^
parentCollectionOfDocument.hashCode ^
parentDocumentOfCollection.hashCode ^
parentDocumentOfStruct.hashCode;
}

class Analyzer {
AnalyzingResult analyze(Schema root) {
final result = AnalyzingResult();

root.collections.forEach((c) => _visitCollection(c, result));

return result;
}

void _visitCollection(Collection collection, AnalyzingResult tmp) {
tmp.definedCollections.add(collection);
tmp.parentCollectionOfDocument[collection.document] = collection;

_visitDocument(collection.document, tmp);
}

void _visitDocument(Document document, AnalyzingResult tmp) {
tmp.definedDocuments.add(document);
tmp.definedStructs.add(document);
tmp.parentDocumentOfStruct[document] = document;

document.fields
.forEach((f) => _visitReferencedType(document, f.type.type, tmp));
document.collections.forEach((c) {
tmp.parentDocumentOfCollection[c] = document;
_visitCollection(c, tmp);
});
}

void _visitReferencedType(
Document document, DeclaredType type, AnalyzingResult tmp) {
if (type is HasStructType) {
tmp.definedStructs.add(type.definition);
tmp.parentDocumentOfStruct[type.definition] = document;
type.definition.fields
.forEach 6D47 ((f) => _visitReferencedType(document, f.type.type, tmp));
} else if (type is HasValueType && type.name == "enum") {
tmp.definedEnums.add(type);
} else if (type is TypedType && type.name == "reference") {
tmp.referenceToDocument.add(type);
} else if (type is TypedType && type.name == "array") {
_visitReferencedType(document, type.typeParameter, tmp);
} else if (type is TypedType && type.name == "struct") {
tmp.embeddedDocuments.add(type);
}
}
}
48 changes: 41 additions & 7 deletions lib/src/ast.dart
F438
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,35 @@ class CollectionParameter {
int get hashCode => name.hashCode ^ value.hashCode;
}

class Document {
class Struct {
String name;
List<DocumentParameter> params = [];
List<Field> fields = [];

Struct(this.name, this.fields);

< 9E81 /td>
@override
bool operator ==(other) =>
identical(this, other) ||
other is Struct &&
runtimeType == other.runtimeType &&
name == other.name &&
fields == other.fields;

@override
int get hashCode => name.hashCode ^ fields.hashCode;

@override
String toString() {
return "Struct $name { $fields }";
}
}

class Document extends Struct {
List<DocumentParameter> params = [];
List<Collection> collections = [];

Document(this.name, this.params, this.fields, this.collections);
Document(String name, this.params, List<Field> fields, this.collections)
: super(name, fields);

@override
String toString() {
Expand Down Expand Up @@ -119,7 +141,7 @@ class DocumentParameter {
}

class Field {
FieldType type;
TypeReference type;
String name;

Field(this.type, this.name);
Expand Down Expand Up @@ -189,11 +211,23 @@ class HasValueType extends DeclaredType {
HasValueType("enum", identity, values);
}

class FieldType {
class HasStructType extends DeclaredType {
final Struct definition;

HasStructType(String name, this.definition) : super(name);

@override
String toString() => "${super.name} $definition";

factory HasStructType.struct(Struct definition) =>
HasStructType("struct", definition);
}

class TypeReference {
DeclaredType type;
bool nullable;

FieldType(this.type, this.nullable);
TypeReference(this.type, this.nullable);

@override
String toString() {
Expand All @@ -203,7 +237,7 @@ class FieldType {
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is FieldType &&
other is TypeReference &&
runtimeType == other.runtimeType &&
type == other.type &&
nullable == other.nullable;
Expand Down
54 changes: 53 additions & 1 deletion lib/src/checker.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:lantern/src/analyzer.dart';
import 'package:lantern/src/ast.dart';

class InvalidParameterError extends Error {
Expand Down Expand Up @@ -39,4 +40,55 @@ class ParameterChecker {
}
}

class TypeChecker {}
class ReferencingUndefinedDocumentError extends Error {
final Set<String> undefineds;

ReferencingUndefinedDocumentError(this.undefineds);

@override
String toString() =>
"Referenced documents below are not defined: ${undefineds.join(", ")}";
}

class EmbeddingUndefinedDocumentError extends Error {
final Set<String> undefineds;

EmbeddingUndefinedDocumentError(this.undefineds);

@override
String toString() =>
"Embedded documents below are not defined: ${undefineds.join(", ")}";
}

class TypeChecker {
void check(AnalyzingResult analyzed) {
_validateDocumentReferencing(analyzed);
_validateStructEmbedding(analyzed);
}

void _validateDocumentReferencing(AnalyzingResult analyzed) {
final unifiedDocuments =
analyzed.definedDocuments.map((d) => d.name).toSet();
final unifiedReferences =
analyzed.referenceToDocument.map((r) => r.typeParameter.name).toSet();

if (!unifiedDocuments.containsAll(unifiedReferences)) {
final undefinedButReferencedDocumentNames =
unifiedReferences.difference(unifiedDocuments);
throw ReferencingUndefinedDocumentError(
undefinedButReferencedDocumentNames);
}
}

void _validateStructEmbedding(AnalyzingResult analyzed) {
final unifiedStructs = analyzed.definedStructs.map((s) => s.name).toSet();
final unifiedEmbddeds =
analyzed.embeddedDocuments.map((d) => d.typeParameter.name).toSet();

if (!unifiedStructs.containsAll(unifiedEmbddeds)) {
final undefinedButEmbeddedDocumentNames =
unifiedEmbddeds.difference(unifiedStructs);
throw EmbeddingUndefinedDocumentError(undefinedButEmbeddedDocumentNames);
}
}
}
Loading
0