This repository has been archived by the owner on Jan 26, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Parameterize uri resolution and parsing of options, use package:path.
This helps make the compiler more configurable to embed it in other systems (like pub transformers) R=cbracken@google.com Review URL: https://chromiumcodereview.appspot.com//269823003
- Loading branch information
Showing
16 changed files
with
246 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ packages | |
.project | ||
.buildlog | ||
out | ||
*.sw? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
part of protoc; | ||
|
||
/// Helper function implementing a generic option parser that reads | ||
/// `request.parameters` and treats each token as either a flag ("name") or a | ||
/// key-value pair ("name=value"). For each option "name", it looks up whether a | ||
/// [SingleOptionParser] exists in [parsers] and delegates the actual parsing of | ||
/// the option to it. Returns `true` if no errors were reported. | ||
bool genericOptionsParser( | ||
CodeGeneratorRequest request, CodeGeneratorResponse response, | ||
Map<String, SingleOptionParser> parsers) { | ||
var parameter = request.parameter != null ? request.parameter : ''; | ||
var options = parameter.trim().split(','); | ||
var map = <String, String>{}; | ||
var errors = []; | ||
|
||
for (var option in options) { | ||
option = option.trim(); | ||
if (option.isEmpty) continue; | ||
var reportError = (details) { | ||
errors.add('Error found trying to parse the option: $option.\n$details'); | ||
}; | ||
|
||
var nameValue = option.split('='); | ||
if (nameValue.length != 1 && nameValue.length != 2) { | ||
reportError('Options should be a single token, or a name=value pair'); | ||
continue; | ||
} | ||
var name = nameValue[0].trim(); | ||
var parser = parsers[name]; | ||
if (parser == null) { | ||
reportError('Unknown option ($name).'); | ||
continue; | ||
} | ||
|
||
var value = nameValue.length > 1 ? nameValue[1].trim() : null; | ||
parser.parse(name, value, reportError); | ||
} | ||
|
||
if (errors.length == 0) return true; | ||
|
||
response.error = errors.join('\n'); | ||
return false; | ||
} | ||
|
||
/// Options expected by the protoc code generation compiler. | ||
class GenerationOptions { | ||
/// Maps a fully qualified field name, to the desired name we wish to | ||
/// generate. For example `MyMessage.has_field` to `HasFld`. | ||
final Map<String, String> fieldNameOverrides; | ||
|
||
GenerationOptions(this.fieldNameOverrides); | ||
} | ||
|
||
/// A parser for a name-value pair option. Options parsed in | ||
/// [genericOptionsParser] delegate to instances of this class to | ||
/// parse the value of a specific option. | ||
abstract class SingleOptionParser { | ||
|
||
/// Parse the [name]=[value] value pair and report any errors to [onError]. If | ||
/// the option is a flag, [value] will be null. Note, [name] is commonly | ||
/// unused. It is provided because [SingleOptionParser] can be registered for | ||
/// multiple option names in [genericOptionsParser]. | ||
void parse(String name, String value, onError(String details)); | ||
} | ||
|
||
/// Parser used by the compiler, which supports the `field_name` option (see | ||
/// [FieldNameOptionParser]) and any additional option added in [parsers]. If | ||
/// [parsers] has a key for `field_name`, it will be ignored. | ||
GenerationOptions parseGenerationOptions( | ||
CodeGeneratorRequest request, CodeGeneratorResponse response, | ||
[Map<String, SingleOptionParser> parsers]) { | ||
var fieldNameOptionParser = new FieldNameOptionParser(); | ||
var map = {}; | ||
if (parsers != null) parsers.forEach((k, v) { map[k] = v; }); | ||
map['field_name'] = fieldNameOptionParser; | ||
if (genericOptionsParser(request, response, map)) { | ||
return new GenerationOptions(fieldNameOptionParser.mappings); | ||
} | ||
return null; | ||
} | ||
|
||
/// A [SingleOptionParser] to parse the `field_name` option. This option | ||
/// overrides the default name given to some fields that would otherwise collide | ||
/// with existing field names in Dart core objects or in [GeneratedMessage]. | ||
/// (see `README.md` for details). | ||
class FieldNameOptionParser implements SingleOptionParser { | ||
/// Maps a fully qualified field name, to the desired name we wish to | ||
/// generate. For example `MyMessage.has_field` to `HasFld`. | ||
final Map<String, String> mappings = {}; | ||
|
||
void parse(String name, String value, onError(String message)) { | ||
if (value == null) { | ||
onError('Invalid field_name option, expected a non-emtpy value.'); | ||
return; | ||
} | ||
|
||
List<String> fromTo = value.split('|'); | ||
if (fromTo.length != 2) { | ||
onError('Invalid field_name option, expected a single "|" separator.'); | ||
return; | ||
} | ||
|
||
var fromName = fromTo[0].trim(); | ||
var toName = fromTo[1].trim(); | ||
if (fromName.isEmpty || toName.isEmpty) { | ||
onError('Invalid field_name option, ' | ||
'"from" and "to" names should not be empty.'); | ||
return; | ||
} | ||
|
||
mappings['.$fromName'] = toName; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
part of protoc; | ||
|
||
/// Configures where output of the protoc compiler should be placed and how to | ||
/// import one generated file from another. | ||
abstract class OutputConfiguration { | ||
|
||
/// Returns [filePath] with it's extension replaced with '.pb.dart'. | ||
String replacePathExtension(String filePath) => | ||
'${path.withoutExtension(filePath)}.pb.dart'; | ||
|
||
/// Returns [file] with it's extension replaced with '.pb.dart'. | ||
Uri replaceUriExtension(Uri file) => | ||
path.url.toUri(replacePathExtension(path.url.fromUri(file))); | ||
|
||
/// Resolves an import URI. Both [source] and [target] are .proto files, | ||
/// where [target] is imported from [source]. The result URI can be used to | ||
/// import [target]'s .pb.dart output from [source]'s .pb.dart output. | ||
Uri resolveImport(Uri target, Uri source); | ||
|
||
/// Returns the path, under the output folder, where the code will be | ||
/// generated for [inputPath]. The input is expected to be a .proto file, | ||
/// while the output is expected to be a .pb.dart file. | ||
Uri outputPathFor(Uri inputPath); | ||
} | ||
|
||
/// Default [OutputConfiguration] that uses the same path as the input | ||
/// file for the output file (just replaces the extension), and that uses | ||
/// relative paths to resolve imports. | ||
class DefaultOutputConfiguration extends OutputConfiguration { | ||
|
||
Uri outputPathFor(Uri input) => replaceUriExtension(input); | ||
|
||
Uri resolveImport(Uri target, Uri source) { | ||
var builder = path.url; | ||
var targetPath = builder.fromUri(target); | ||
var sourceDir = builder.dirname(builder.fromUri(source)); | ||
return builder.toUri(replacePathExtension( | ||
builder.relative(targetPath, from: sourceDir))); | ||
} | ||
} |
Oops, something went wrong.