This commit is contained in:
thosakwe 2017-02-22 21:48:08 -05:00
parent f07211328f
commit 80a31575aa
9 changed files with 662 additions and 295 deletions

View file

@ -1,19 +1,20 @@
import 'dart:io'; import 'dart:io';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:code_builder/code_builder.dart';
import 'package:console/console.dart'; import 'package:console/console.dart';
import 'package:id/id.dart'; import 'package:inflection/inflection.dart';
import 'package:recase/recase.dart'; import 'package:recase/recase.dart';
import 'service_generators/service_generators.dart';
import 'init.dart' show preBuild; import 'init.dart' show preBuild;
const List<ServiceGenerator> GENERATORS = const [
const MapServiceGenerator(),
const MongoServiceGenerator(),
const RethinkServiceGenerator(),
const CustomServiceGenerator()
];
class ServiceCommand extends Command { class ServiceCommand extends Command {
final String CUSTOM = 'Custom';
final String MEMORY = 'In-Memory';
final String MEMORY_JSON = 'In-Memory (serialized via `source_gen`)';
final String MONGO = 'MongoDB';
final String MONGO_TYPED = 'MongoDB (typed)';
final String MONGO_TYPED_JSON =
'MongoDB (typed, serialized via `source_gen`)';
final String TRESTLE = 'Trestle';
final TextPen _pen = new TextPen(); final TextPen _pen = new TextPen();
@override @override
@ -22,130 +23,146 @@ class ServiceCommand extends Command {
@override @override
String get description => 'Creates a new service within the given project.'; String get description => 'Creates a new service within the given project.';
String _snake(name) => idFromString(name).snake;
@override @override
run() async { run() async {
var name = await readInput('Name of Service (not plural): '); var name = await readInput('Name of Service (not plural): ');
var chooser = new Chooser([MONGO, MONGO_TYPED, MEMORY, CUSTOM], var chooser = new Chooser<String>(
GENERATORS.map<String>((g) => g.name).toList(),
message: 'What type of service would you like to create? '); message: 'What type of service would you like to create? ');
var type = await chooser.choose(); var type = await chooser.choose();
fail() { print('Wrap this service in a TypedService? (slight performance cost)');
_pen.red(); chooser = new Chooser<String>(['Yes', 'No']);
_pen('Could not successfully create service $name.'); var typed = (await chooser.choose()) == 'Yes';
_pen();
}
String serviceSource = ''; var generator =
GENERATORS.firstWhere((g) => g.name == type, orElse: () => null);
if (type == MONGO) { if (generator == null) {
serviceSource = _generateMongoService(name);
} else if (type == MONGO_TYPED) {
serviceSource = _generateMongoTypedService(name);
await _generateMongoModel(name);
await _generateValidator(name);
} else if (type == MONGO_TYPED_JSON) {
serviceSource = _generateMongoTypedService(name);
await _generateMongoModelJson(name);
await _generateValidator(name);
} else if (type == MEMORY) {
serviceSource = _generateMemoryService(name);
await _generateMemoryModel(name);
await _generateValidator(name);
} else if (type == MEMORY_JSON) {
serviceSource = _generateMemoryService(name);
await _generateMemoryModelJson(name);
await _generateValidator(name);
} else if (type == CUSTOM) {
serviceSource = _generateCustomService(name);
} else if (type == TRESTLE) {
_pen.blue(); _pen.blue();
_pen('${Icon.STAR} Trestle services are not yet implemented. :('); _pen('${Icon.STAR} \'$type\' services are not yet implemented. :(');
_pen(); _pen();
} else { } else {
print('Code to generate a $type service is not yet written.'); var rc = new ReCase(name);
} name = rc.pascalCase;
var lower = rc.snakeCase;
if (serviceSource.isEmpty) {
fail();
throw new Exception('Empty generated service code.');
}
var lower = _snake(name);
var servicesDir = new Directory('lib/src/services'); var servicesDir = new Directory('lib/src/services');
var serviceFile = new File.fromUri(servicesDir.uri.resolve('$lower.dart')); var serviceFile =
new File.fromUri(servicesDir.uri.resolve('$lower.dart'));
var testDir = new Directory('test/services'); var testDir = new Directory('test/services');
var testFile = new File.fromUri(testDir.uri.resolve('${lower}_test.dart')); var testFile =
new File.fromUri(testDir.uri.resolve('${lower}_test.dart'));
if (!await servicesDir.exists()) await servicesDir.create(recursive: true);
if (!await servicesDir.exists())
await servicesDir.create(recursive: true);
if (!await testDir.exists()) await testDir.create(recursive: true); if (!await testDir.exists()) await testDir.create(recursive: true);
await serviceFile.writeAsString(serviceSource); await serviceFile
.writeAsString(_generateService(generator, name, lower, typed));
if (type == MONGO_TYPED || type == MEMORY) { await testFile.writeAsString(_generateTests(lower, type));
var serviceLibrary = new File('lib/src/models/models.dart');
await serviceLibrary.writeAsString("\nexport '$lower.dart';",
mode: FileMode.APPEND);
await preBuild(Directory.current);
}
await testFile.writeAsString(_generateTests(name, type));
var runConfig = new File('./.idea/runConfigurations/${name}_Tests.xml'); var runConfig = new File('./.idea/runConfigurations/${name}_Tests.xml');
if (!await runConfig.exists()) { if (!await runConfig.exists()) {
await runConfig.create(recursive: true); await runConfig.create(recursive: true);
await runConfig.writeAsString(_generateRunConfiguration(name)); await runConfig.writeAsString(_generateRunConfiguration(name, lower));
}
if (generator.createsModel == true) {
await _generateModel(name, lower);
}
if (generator.createsValidator == true) {
await _generateValidator(lower, rc.constantCase);
}
if (generator.exportedInServiceLibrary == true) {
var serviceLibrary = new File('lib/src/models/models.dart');
await serviceLibrary.writeAsString("\nexport '$lower.dart';",
mode: FileMode.APPEND);
}
if (generator.shouldRunBuild == true) {
await preBuild(Directory.current);
} }
_pen.green(); _pen.green();
_pen('${Icon.CHECKMARK} Successfully generated service $name.'); _pen('${Icon.CHECKMARK} Successfully generated service $name.');
_pen(); _pen();
} }
_generateValidator(String name) async {
var rc = new ReCase(name);
var file = new File('lib/src/validators/${rc.snakeCase}.dart');
if (!await file.exists()) await file.createSync(recursive: true);
await file.writeAsString('''
import 'package:angel_validate/angel_validate.dart';
final Validator CREATE_${rc.constantCase} =
new Validator({'name*': isString, 'desc*': isString});
'''
.trim());
} }
_generateCustomService(String name) { String _generateService(
return ''' ServiceGenerator generator, String name, String lower, bool typed) {
var lib = new LibraryBuilder();
/*
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import '../models/$lower.dart';
export '../models/$lower.dart';
*/
lib.addMember(
new ImportBuilder('package:angel_framework/angel_framework.dart'));
generator.applyToLibrary(lib, name, lower);
class ${name}Service extends Service { if (generator.createsModel == true) {
${name}Service():super() { lib
// Your logic here! ..addMember(new ImportBuilder('../models/$lower.dart'))
} ..addMember(new ExportBuilder('../models/$lower.dart'));
}
'''
.trim();
} }
_generateMemoryModel(String name) async { // configureServer() {}
var lower = _snake(name); var configureServer = new MethodBuilder('configureServer',
returnType: new TypeBuilder('AngelConfigurer'));
generator.applyToConfigureServer(configureServer, name, lower);
// return (Angel app) async {}
var closure = new MethodBuilder.closure(modifier: MethodModifier.asAsync)
..addPositional(parameter('app', [new TypeBuilder('Angel')]));
generator.beforeService(closure, name, lower);
// app.use('/api/todos', new MapService());
var service = generator.createInstance(closure, name, lower);
if (typed == true) {
service =
new TypeBuilder('TypedService', genericTypes: [new TypeBuilder(name)])
.newInstance([service]);
}
closure.addStatement(reference('app')
.invoke('use', [literal('/api/${pluralize(lower)}'), service]));
if (generator.injectsSingleton == true) {
closure.addStatement(varField('service',
value: reference('app')
.invoke('service', [literal('/api/${pluralize(lower)}')]).castAs(
new TypeBuilder('HookedService'))));
closure.addStatement(reference('app')
.property('container')
.invoke('singleton', [reference('service').property('inner')]));
}
configureServer.addStatement(closure.asReturn());
lib.addMember(configureServer);
return prettyToSource(lib.buildAst());
}
_generateModel(String name, String lower) async {
var file = new File('lib/src/models/$lower.dart'); var file = new File('lib/src/models/$lower.dart');
if (!await file.exists()) await file.createSync(recursive: true); if (!await file.exists()) await file.createSync(recursive: true);
await file.writeAsString(''' await file.writeAsString('''
library angel.models.$lower;
import 'package:angel_framework/common.dart'; import 'package:angel_framework/common.dart';
class $name extends Model { class $name extends Model {
String name, desc; String name;
String desc;
$name({String id, this.name, this.desc}) { $name({String id, this.name, this.desc}) {
this.id = id; this.id = id;
@ -155,197 +172,21 @@ class $name extends Model {
.trim()); .trim());
} }
_generateMemoryModelJson(String name) async { _generateValidator(String lower, String constantCase) async {
var lower = _snake(name); var file = new File('lib/src/validators/$lower.dart');
var file = new File('lib/src/models/$lower.dart');
if (!await file.exists()) await file.createSync(recursive: true); if (!await file.exists()) await file.createSync(recursive: true);
await file.writeAsString(''' await file.writeAsString('''
library angel.models.$lower;
import 'package:angel_framework/common.dart';
import 'package:source_gen/generators/json_serializable.dart';
part '$lower.g.dart';
@JsonSerializable()
class $name extends Model with _\$${name}SerializerMixin {
@JsonKey('id')
@override
String id;
@JsonKey('name')
String name;
@JsonKey('desc')
String desc;
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
$name({this.id, this.name, this.desc});
}
'''
.trim());
}
_generateMemoryService(String name) {
var rc = new ReCase(name);
var lower = rc.snakeCase;
return '''
import 'package:angel_framework/angel_framework.dart';
import '../models/$lower.dart';
export '../models/$lower.dart';
/// Manages [$name] in-memory.
class ${name}Service extends MemoryService<$name> {
${name}Service():super() {
// Your logic here!
}
}
'''
.trim();
}
_generateMongoModel(String name) async {
var lower = _snake(name);
var file = new File('lib/src/models/$lower.dart');
if (!await file.exists()) await file.createSync(recursive: true);
await file.writeAsString('''
library angel.models.$lower;
import 'package:angel_mongo/model.dart';
import 'package:source_gen/generators/json_serializable.dart';
part '$lower.g.dart';
@JsonSerializable()
class $name extends Model with _\$${name}SerializerMixin {
@JsonKey('id')
@override
String id;
@JsonKey('name')
String name;
@JsonKey('desc')
String desc;
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
$name({this.id, this.name, this.desc});
}
'''
.trim());
}
_generateMongoModelJson(String name) async {
var lower = _snake(name);
var file = new File('lib/src/models/$lower.dart');
if (!await file.exists()) await file.createSync(recursive: true);
await file.writeAsString('''
library angel.models.$lower;
import 'package:angel_framework/common.dart';
import 'package:source_gen/generators/json_serializable.dart';
part '$lower.g.dart';
@JsonSerializable()
class $name extends Model with _\$${name}SerializerMixin {
@JsonKey('id')
@override
String id;
@JsonKey('name')
String name;
@JsonKey('desc')
String desc;
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
$name({this.id, this.name, this.desc});
}
'''
.trim());
}
_generateMongoService(String name) {
var lower = _snake(name);
return '''
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_mongo/angel_mongo.dart';
import 'package:angel_validate/angel_validate.dart'; import 'package:angel_validate/angel_validate.dart';
import 'package:angel_validate/server.dart';
import 'package:mongo_dart/mongo_dart.dart';
final Validator ${lower}Schema = new Validator({ final Validator CREATE_$constantCase =
'name*': [isString, isNotEmpty], new Validator({'name*': isString, 'desc*': isString});
'desc*': [isString, isNotEmpty]
});
configureServer(Db db) {
return (Angel app) async {
app.use('/api/${lower}s', new ${name}Service(db.collection('${lower}s')));
HookedService service = app.service('api/${lower}s');
app.container.singleton(service.inner);
service
..beforeCreate.listen(validateEvent(${lower}Schema))
..beforeUpdate.listen(validateEvent(${lower}Schema));
};
}
/// Manages [$name] in the database.
class ${name}Service extends MongoService {
${name}Service(collection):super(collection) {
// Your logic here!
}
}
''' '''
.trim(); .trim());
} }
_generateMongoTypedService(String name) { _generateRunConfiguration(String name, String lower) {
var lower = _snake(name);
return '''
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_mongo/angel_mongo.dart';
import 'package:mongo_dart/mongo_dart.dart';
import '../models/$lower.dart';
export '../models/$lower.dart';
configureServer(Db db) {
return (Angel app) async {
app.use('/api/${lower}s', new ${name}Service(db.collection('${lower}s')));
HookedService service = app.service('api/${lower}s');
app.container.singleton(service.inner);
};
}
/// Manages [$name] in the database.
class ${name}Service extends MongoTypedService<$name> {
${name}Service(collection):super(collection) {
// Your logic here!
}
}
'''
.trim();
}
_generateRunConfiguration(String name) {
var lower = _snake(name);
return ''' return '''
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="$name Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true"> <configuration default="false" name="$name Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true">
@ -357,9 +198,7 @@ class ${name}Service extends MongoTypedService<$name> {
.trim(); .trim();
} }
_generateTests(String name, String type) { _generateTests(String lower, String type) {
var lower = _snake(name);
return ''' return '''
import 'dart:io'; import 'dart:io';
import 'package:angel/angel.dart'; import 'package:angel/angel.dart';
@ -382,13 +221,13 @@ main() async {
}); });
test('index via REST', () async { test('index via REST', () async {
var response = await client.get('/api/${lower}s'); var response = await client.get('/api/${pluralize(lower)}');
expect(response, hasStatus(HttpStatus.OK)); expect(response, hasStatus(HttpStatus.OK));
}); });
test('Index ${lower}s', () async { test('Index ${pluralize(lower)}', () async {
var ${lower}s = await client.service('api/${lower}s').index(); var ${pluralize(lower)} = await client.service('api/${pluralize(lower)}').index();
print(${lower}s); print(${pluralize(lower)});
}); });
} }

View file

@ -0,0 +1,24 @@
import 'package:code_builder/code_builder.dart';
import 'generator.dart';
class CustomServiceGenerator extends ServiceGenerator {
@override
bool get createsModel => false;
@override
bool get createsValidator => false;
const CustomServiceGenerator() : super('Custom');
@override
void applyToLibrary(LibraryBuilder library, String name, String lower) {
var clazz = new ClassBuilder('${name}Service', asExtends: new TypeBuilder('Service'));
library.addMember(clazz);
}
@override
ExpressionBuilder createInstance(
MethodBuilder methodBuilder, String name, String lower) {
return new TypeBuilder('${name}Service').newInstance([]);
}
}

View file

@ -0,0 +1,24 @@
import 'package:code_builder/code_builder.dart';
class ServiceGenerator {
final String name;
const ServiceGenerator(this.name);
bool get createsModel => true;
bool get createsValidator => true;
bool get exportedInServiceLibrary => true;
bool get injectsSingleton => true;
bool get shouldRunBuild => false;
void applyToLibrary(LibraryBuilder library, String name, String lower) {}
void beforeService(MethodBuilder methodBuilder, String name, String lower) {}
void applyToConfigureServer(
MethodBuilder configureServer, String name, String lower) {}
ExpressionBuilder createInstance(
MethodBuilder methodBuilder, String name, String lower) =>
literal(null);
}

View file

@ -0,0 +1,15 @@
import 'generator.dart';
import 'package:code_builder/code_builder.dart';
class MapServiceGenerator extends ServiceGenerator {
@override
bool get createsModel => false;
const MapServiceGenerator() : super('In-Memory');
@override
ExpressionBuilder createInstance(
MethodBuilder methodBuilder, String name, String lower) {
return new TypeBuilder('MapService').newInstance([]);
}
}

View file

@ -0,0 +1,29 @@
import 'generator.dart';
import 'package:code_builder/code_builder.dart';
import 'package:inflection/inflection.dart';
class MongoServiceGenerator extends ServiceGenerator {
const MongoServiceGenerator() : super('MongoDB');
@override
void applyToConfigureServer(
MethodBuilder configureServer, String name, String lower) {
configureServer.addPositional(parameter('db', [new TypeBuilder('Db')]));
}
@override
void applyToLibrary(LibraryBuilder library, String name, String lower) {
library.addMembers([
'package:angel_mongo/angel_mongo.dart',
'package:mongo_dart/mongo_dart.dart'
].map((str) => new ImportBuilder(str)));
}
@override
ExpressionBuilder createInstance(
MethodBuilder methodBuilder, String name, String lower) {
return new TypeBuilder('MongoService').newInstance([
reference('db').invoke('collection', [literal(pluralize(lower))])
]);
}
}

View file

@ -0,0 +1,31 @@
import 'generator.dart';
import 'package:code_builder/code_builder.dart';
import 'package:inflection/inflection.dart';
class RethinkServiceGenerator extends ServiceGenerator {
const RethinkServiceGenerator() : super('RethinkDB');
@override
void applyToConfigureServer(
MethodBuilder configureServer, String name, String lower) {
configureServer
..addPositional(parameter('connection', [new TypeBuilder('Connection')]))
..addPositional(parameter('r', [new TypeBuilder('Rethinkdb')]));
}
@override
void applyToLibrary(LibraryBuilder library, String name, String lower) {
library.addMembers([
'package:angel_rethink/angel_rethink.dart',
'package:rethinkdb_driver/rethinkdb_driver.dart'
].map((str) => new ImportBuilder(str)));
}
@override
ExpressionBuilder createInstance(
MethodBuilder methodBuilder, String name, String lower) {
return new TypeBuilder('RethinkService').newInstance([
reference('r').invoke('table', [literal(pluralize(lower))])
]);
}
}

View file

@ -0,0 +1,5 @@
export 'custom.dart';
export 'generator.dart';
export 'map.dart';
export 'mongo.dart';
export 'rethink.dart';

View file

@ -0,0 +1,398 @@
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:console/console.dart';
import 'package:id/id.dart';
import 'package:recase/recase.dart';
import 'init.dart' show preBuild;
class ServiceCommand extends Command {
final String CUSTOM = 'Custom';
final String MEMORY = 'In-Memory';
final String MEMORY_JSON = 'In-Memory (serialized via `source_gen`)';
final String MONGO = 'MongoDB';
final String MONGO_TYPED = 'MongoDB (typed)';
final String MONGO_TYPED_JSON =
'MongoDB (typed, serialized via `source_gen`)';
final String TRESTLE = 'Trestle';
final TextPen _pen = new TextPen();
@override
String get name => 'service';
@override
String get description => 'Creates a new service within the given project.';
String _snake(name) => idFromString(name).snake;
@override
run() async {
var name = await readInput('Name of Service (not plural): ');
var chooser = new Chooser([MONGO, MONGO_TYPED, MEMORY, CUSTOM],
message: 'What type of service would you like to create? ');
var type = await chooser.choose();
fail() {
_pen.red();
_pen('Could not successfully create service $name.');
_pen();
}
String serviceSource = '';
if (type == MONGO) {
serviceSource = _generateMongoService(name);
} else if (type == MONGO_TYPED) {
serviceSource = _generateMongoTypedService(name);
await _generateMongoModel(name);
await _generateValidator(name);
} else if (type == MONGO_TYPED_JSON) {
serviceSource = _generateMongoTypedService(name);
await _generateMongoModelJson(name);
await _generateValidator(name);
} else if (type == MEMORY) {
serviceSource = _generateMemoryService(name);
await _generateMemoryModel(name);
await _generateValidator(name);
} else if (type == MEMORY_JSON) {
serviceSource = _generateMemoryService(name);
await _generateMemoryModelJson(name);
await _generateValidator(name);
} else if (type == CUSTOM) {
serviceSource = _generateCustomService(name);
} else if (type == TRESTLE) {
_pen.blue();
_pen('${Icon.STAR} Trestle services are not yet implemented. :(');
_pen();
} else {
print('Code to generate a $type service is not yet written.');
}
if (serviceSource.isEmpty) {
fail();
throw new Exception('Empty generated service code.');
}
var lower = _snake(name);
var servicesDir = new Directory('lib/src/services');
var serviceFile = new File.fromUri(servicesDir.uri.resolve('$lower.dart'));
var testDir = new Directory('test/services');
var testFile = new File.fromUri(testDir.uri.resolve('${lower}_test.dart'));
if (!await servicesDir.exists()) await servicesDir.create(recursive: true);
if (!await testDir.exists()) await testDir.create(recursive: true);
await serviceFile.writeAsString(serviceSource);
if (type == MONGO_TYPED || type == MEMORY) {
var serviceLibrary = new File('lib/src/models/models.dart');
await serviceLibrary.writeAsString("\nexport '$lower.dart';",
mode: FileMode.APPEND);
await preBuild(Directory.current);
}
await testFile.writeAsString(_generateTests(name, type));
var runConfig = new File('./.idea/runConfigurations/${name}_Tests.xml');
if (!await runConfig.exists()) {
await runConfig.create(recursive: true);
await runConfig.writeAsString(_generateRunConfiguration(name));
}
_pen.green();
_pen('${Icon.CHECKMARK} Successfully generated service $name.');
_pen();
}
_generateValidator(String name) async {
var rc = new ReCase(name);
var file = new File('lib/src/validators/${rc.snakeCase}.dart');
if (!await file.exists()) await file.createSync(recursive: true);
await file.writeAsString('''
import 'package:angel_validate/angel_validate.dart';
final Validator CREATE_${rc.constantCase} =
new Validator({'name*': isString, 'desc*': isString});
'''
.trim());
}
_generateCustomService(String name) {
return '''
import 'package:angel_framework/angel_framework.dart';
class ${name}Service extends Service {
${name}Service():super() {
// Your logic here!
}
}
'''
.trim();
}
_generateMemoryModel(String name) async {
var lower = _snake(name);
var file = new File('lib/src/models/$lower.dart');
if (!await file.exists()) await file.createSync(recursive: true);
await file.writeAsString('''
library angel.models.$lower;
import 'package:angel_framework/common.dart';
class $name extends Model {
String name, desc;
$name({String id, this.name, this.desc}) {
this.id = id;
}
}
'''
.trim());
}
_generateMemoryModelJson(String name) async {
var lower = _snake(name);
var file = new File('lib/src/models/$lower.dart');
if (!await file.exists()) await file.createSync(recursive: true);
await file.writeAsString('''
library angel.models.$lower;
import 'package:angel_framework/common.dart';
import 'package:source_gen/generators/json_serializable.dart';
part '$lower.g.dart';
@JsonSerializable()
class $name extends Model with _\$${name}SerializerMixin {
@JsonKey('id')
@override
String id;
@JsonKey('name')
String name;
@JsonKey('desc')
String desc;
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
$name({this.id, this.name, this.desc});
}
'''
.trim());
}
_generateMemoryService(String name) {
var rc = new ReCase(name);
var lower = rc.snakeCase;
return '''
import 'package:angel_framework/angel_framework.dart';
import '../models/$lower.dart';
export '../models/$lower.dart';
/// Manages [$name] in-memory.
class ${name}Service extends MemoryService<$name> {
${name}Service():super() {
// Your logic here!
}
}
'''
.trim();
}
_generateMongoModel(String name) async {
var lower = _snake(name);
var file = new File('lib/src/models/$lower.dart');
if (!await file.exists()) await file.createSync(recursive: true);
await file.writeAsString('''
library angel.models.$lower;
import 'package:angel_mongo/model.dart';
import 'package:source_gen/generators/json_serializable.dart';
part '$lower.g.dart';
@JsonSerializable()
class $name extends Model with _\$${name}SerializerMixin {
@JsonKey('id')
@override
String id;
@JsonKey('name')
String name;
@JsonKey('desc')
String desc;
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
$name({this.id, this.name, this.desc});
}
'''
.trim());
}
_generateMongoModelJson(String name) async {
var lower = _snake(name);
var file = new File('lib/src/models/$lower.dart');
if (!await file.exists()) await file.createSync(recursive: true);
await file.writeAsString('''
library angel.models.$lower;
import 'package:angel_framework/common.dart';
import 'package:source_gen/generators/json_serializable.dart';
part '$lower.g.dart';
@JsonSerializable()
class $name extends Model with _\$${name}SerializerMixin {
@JsonKey('id')
@override
String id;
@JsonKey('name')
String name;
@JsonKey('desc')
String desc;
factory $name.fromJson(Map json) => _\$${name}FromJson(json);
$name({this.id, this.name, this.desc});
}
'''
.trim());
}
_generateMongoService(String name) {
var lower = _snake(name);
return '''
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_mongo/angel_mongo.dart';
import 'package:angel_validate/angel_validate.dart';
import 'package:angel_validate/server.dart';
import 'package:mongo_dart/mongo_dart.dart';
final Validator ${lower}Schema = new Validator({
'name*': [isString, isNotEmpty],
'desc*': [isString, isNotEmpty]
});
configureServer(Db db) {
return (Angel app) async {
app.use('/api/${lower}s', new ${name}Service(db.collection('${lower}s')));
HookedService service = app.service('api/${lower}s');
app.container.singleton(service.inner);
service
..beforeCreate.listen(validateEvent(${lower}Schema))
..beforeUpdate.listen(validateEvent(${lower}Schema));
};
}
/// Manages [$name] in the database.
class ${name}Service extends MongoService {
${name}Service(collection):super(collection) {
// Your logic here!
}
}
'''
.trim();
}
_generateMongoTypedService(String name) {
var lower = _snake(name);
return '''
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_mongo/angel_mongo.dart';
import 'package:mongo_dart/mongo_dart.dart';
import '../models/$lower.dart';
export '../models/$lower.dart';
configureServer(Db db) {
return (Angel app) async {
app.use('/api/${lower}s', new ${name}Service(db.collection('${lower}s')));
HookedService service = app.service('api/${lower}s');
app.container.singleton(service.inner);
};
}
/// Manages [$name] in the database.
class ${name}Service extends MongoTypedService<$name> {
${name}Service(collection):super(collection) {
// Your logic here!
}
}
'''
.trim();
}
_generateRunConfiguration(String name) {
var lower = _snake(name);
return '''
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="$name Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true">
<option name="filePath" value="\$PROJECT_DIR\$/test/services/${lower}_test.dart" />
<method />
</configuration>
</component>
'''
.trim();
}
_generateTests(String name, String type) {
var lower = _snake(name);
return '''
import 'dart:io';
import 'package:angel/angel.dart';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_test/angel_test.dart';
import 'package:test/test.dart';
main() async {
Angel app;
TestClient client;
setUp(() async {
app = await createServer();
client = await connectTo(app);
});
tearDown(() async {
await client.close();
app = null;
});
test('index via REST', () async {
var response = await client.get('/api/${lower}s');
expect(response, hasStatus(HttpStatus.OK));
});
test('Index ${lower}s', () async {
var ${lower}s = await client.service('api/${lower}s').index();
print(${lower}s);
});
}
'''
.trim();
}
}

View file

@ -2,13 +2,15 @@ author: "Tobe O <thosakwe@gmail.com>"
description: "Command-line tools for the Angel framework." description: "Command-line tools for the Angel framework."
homepage: "https://github.com/angel-dart/angel_cli" homepage: "https://github.com/angel-dart/angel_cli"
name: "angel_cli" name: "angel_cli"
version: "1.0.0" version: "1.0.1"
dependencies: dependencies:
analyzer: "^0.29.0" analyzer: "^0.29.0"
args: "^0.13.7" args: "^0.13.7"
code_builder: "^1.0.0-alpha"
console: "^2.2.3" console: "^2.2.3"
glob: "^1.1.0" glob: "^1.1.0"
id: "^1.0.0" id: "^1.0.0"
inflection: "^0.4.1"
pubspec: "^0.0.14" pubspec: "^0.0.14"
random_string: "^0.0.1" random_string: "^0.0.1"
recase: "^1.0.0" recase: "^1.0.0"