mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 09:43:08 +00:00
303efec911
BUG= R=paulberry@google.com Review-Url: https://codereview.chromium.org/2916023004 .
251 lines
8.1 KiB
Dart
251 lines
8.1 KiB
Dart
// Copyright (c) 2015, 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.
|
|
|
|
import 'dart:convert';
|
|
import 'dart:io' as io;
|
|
|
|
import 'package:dart_messages/shared_messages.dart';
|
|
|
|
const String jsonPath = '../lib/generated/shared_messages.json';
|
|
const String dart2jsPath =
|
|
'../../compiler/lib/src/diagnostics/generated/shared_messages.dart';
|
|
const String analyzerPath =
|
|
'../../analyzer/lib/src/generated/generated/shared_messages.dart';
|
|
|
|
final String dontEditWarning = """
|
|
/*
|
|
DON'T EDIT. GENERATED. DON'T EDIT.
|
|
This file has been generated by 'publish.dart' in the dart_messages package.
|
|
|
|
Messages are maintained in `lib/shared_messages.dart` of that same package.
|
|
After any change to that file, run `bin/publish.dart` to generate a new version
|
|
of the json, dart2js and analyzer representations.
|
|
*/""";
|
|
|
|
const String copyrightHeader = '''
|
|
// Copyright (c) 2015, 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.''';
|
|
|
|
void markAsReadonly(String path) {
|
|
// TODO(15078): mark as read-only. Currently not possible:
|
|
// http://dartbug.com/15078.
|
|
}
|
|
|
|
void emitJson() {
|
|
var input = MESSAGES;
|
|
var outPath = io.Platform.script.resolve(jsonPath).toFilePath();
|
|
print("Emitting JSON:");
|
|
print(" Input: ${input.length} entries");
|
|
print(" Output: $outPath");
|
|
new io.File(outPath).writeAsStringSync(messagesAsJson);
|
|
print("Emitting JSON done.");
|
|
}
|
|
|
|
/// Escapes the given string [str].
|
|
///
|
|
/// The parameter [str] may be `null` in which case the result is "null".
|
|
String escapeString(String str) {
|
|
return JSON.encode(str);
|
|
}
|
|
|
|
/// Emits the messages in dart2js format.
|
|
///
|
|
/// The dart2js-format consists of two entities:
|
|
/// 1. the `MessageKind` enum, and
|
|
/// 2. the MessageKind-to-Template map `TEMPLATES`.
|
|
///
|
|
/// The template is an instance of MessageTemplate:
|
|
///
|
|
/// const MessageTemplate(
|
|
/// this.kind,
|
|
/// this.template,
|
|
/// {this.howToFix,
|
|
/// this.examples,
|
|
/// this.options: const <String>[]});
|
|
///
|
|
/// A sample output thus looks as follows:
|
|
///
|
|
/// enum MessageKind {
|
|
/// EXAMPLE_MESSAGE,
|
|
/// }
|
|
///
|
|
/// const Map<MessageKind, MessageTemplate> {
|
|
/// EXAMPLE_MESSAGE: const MessageTemplate(
|
|
/// EXAMPLE_MESSAGE,
|
|
/// "Don't use #foo with #bar",
|
|
/// howToFix: "Just don't do it",
|
|
/// options: const ['--some-flag']),
|
|
/// examples: const ['''
|
|
/// some example with bad code;'''],
|
|
/// };
|
|
void emitDart2js() {
|
|
var input = MESSAGES;
|
|
var outPath = io.Platform.script.resolve(dart2jsPath).toFilePath();
|
|
print("Emitting dart2js:");
|
|
print(" Input: ${input.length} entries");
|
|
print(" Output: $outPath");
|
|
|
|
StringBuffer out = new StringBuffer();
|
|
out.writeln(copyrightHeader);
|
|
out.writeln(dontEditWarning);
|
|
out.writeln("import '../messages.dart' show MessageKind, MessageTemplate;");
|
|
out.writeln();
|
|
out.writeln("const Map<MessageKind, MessageTemplate> TEMPLATES = "
|
|
"const <MessageKind, MessageTemplate>{ ");
|
|
input.forEach((name, message) {
|
|
if (!message.usedBy.contains(Platform.dart2js)) return;
|
|
|
|
out.writeln(" MessageKind.$name: const MessageTemplate(");
|
|
// TODO(floitsch): include id.
|
|
out.writeln(" MessageKind.$name,");
|
|
out.write(" ");
|
|
out.write(escapeString(message.template));
|
|
if (message.howToFix != null) {
|
|
out.write(",\n howToFix: ${escapeString(message.howToFix)}");
|
|
}
|
|
if (message.options != null) {
|
|
out.write(",\n options: const [");
|
|
out.write(message.options.map(escapeString).join(","));
|
|
out.writeln("]");
|
|
}
|
|
if (message.examples != null) {
|
|
out.writeln(",\n examples: const [");
|
|
|
|
String escapeExampleContent(String content) {
|
|
if (content.contains("\n") || content.contains('"')) {
|
|
return 'r"""\n$content"""';
|
|
} else if (content.contains("\\")) {
|
|
return 'r"$content"';
|
|
}
|
|
return '"$content"';
|
|
}
|
|
|
|
for (var example in message.examples) {
|
|
if (example is String) {
|
|
out.write(" ");
|
|
out.write(escapeExampleContent(example));
|
|
} else if (example is Map) {
|
|
out.writeln(" const {");
|
|
example.forEach((String fileName, String content) {
|
|
out.writeln(" '$fileName': ");
|
|
out.write(escapeExampleContent(content));
|
|
out.writeln(",");
|
|
});
|
|
out.write(" }");
|
|
}
|
|
out.writeln(",");
|
|
}
|
|
out.writeln(" ]");
|
|
}
|
|
out.writeln(" ), // Generated. Don't edit.");
|
|
});
|
|
out.writeln("};");
|
|
|
|
new io.File(outPath).writeAsStringSync(out.toString());
|
|
print("Emitting dart2js done.");
|
|
}
|
|
|
|
String convertToAnalyzerTemplate(String template, holeOrder) {
|
|
var holeMap;
|
|
if (holeOrder != null) {
|
|
holeMap = {};
|
|
for (int i = 0; i < holeOrder.length; i++) {
|
|
holeMap[holeOrder[i]] = i;
|
|
}
|
|
}
|
|
int seenHoles = 0;
|
|
return template.replaceAllMapped(new RegExp(r"#\w+|#{\w+}"), (Match match) {
|
|
if (holeMap != null) {
|
|
String matchedString = match[0];
|
|
String holeName = matchedString.startsWith("#{")
|
|
? matchedString.substring(2, matchedString.length - 1)
|
|
: matchedString.substring(1);
|
|
int index = holeMap[holeName];
|
|
if (index == null) {
|
|
throw "Couldn't find hole-position for $holeName $holeMap";
|
|
}
|
|
return "{$index}";
|
|
} else {
|
|
return "{${seenHoles++}}";
|
|
}
|
|
});
|
|
}
|
|
|
|
String camlToAllCaps(String input) {
|
|
StringBuffer out = new StringBuffer();
|
|
for (int i = 0; i < input.length; i++) {
|
|
String c = input[i];
|
|
if (c.toUpperCase() == c) {
|
|
out.write("_$c");
|
|
} else {
|
|
out.write(c.toUpperCase());
|
|
}
|
|
}
|
|
return out.toString();
|
|
}
|
|
|
|
/// Emits the messages in analyzer format.
|
|
///
|
|
/// Messages are encoded as instances of `ErrorCode` classes where the
|
|
/// corresponding class is given by the `category` field of the Message.
|
|
///
|
|
/// All instances are stored as top-level const variables.
|
|
///
|
|
/// A sample output looks as follows:
|
|
///
|
|
/// const FooCategoryErrorCode EXAMPLE_MESSAGE = const FooCategoryErrorCode(
|
|
/// "EXAMPLE_MESSAGE",
|
|
/// "Don't use {0} with {1}",
|
|
/// "Just don't do it");
|
|
void emitAnalyzer() {
|
|
var input = MESSAGES;
|
|
var outPath = io.Platform.script.resolve(analyzerPath).toFilePath();
|
|
print("Emitting analyzer:");
|
|
print(" Input: ${input.length} entries");
|
|
print(" Output: $outPath");
|
|
|
|
StringBuffer out = new StringBuffer();
|
|
out.writeln(copyrightHeader);
|
|
out.writeln(dontEditWarning);
|
|
out.writeln("import 'package:analyzer/src/generated/error.dart';");
|
|
out.writeln("import 'package:analyzer/src/generated/parser.dart' "
|
|
"show ParserErrorCode;");
|
|
input.forEach((name, message) {
|
|
if (!message.usedBy.contains(Platform.analyzer)) return;
|
|
List<Category> categories = message.categories;
|
|
bool hasMultipleCategories = categories.length != 1;
|
|
for (Category category in categories) {
|
|
String className = category.name + "Code";
|
|
String analyzerName =
|
|
hasMultipleCategories ? "$name${camlToAllCaps(category.name)}" : name;
|
|
out.writeln();
|
|
out.writeln("const $className $analyzerName = const $className(");
|
|
out.writeln(" '$name',");
|
|
|
|
String template = message.template;
|
|
List holeOrder = message.templateHoleOrder;
|
|
String analyzerTemplate = convertToAnalyzerTemplate(template, holeOrder);
|
|
out.write(" ");
|
|
out.write(escapeString(analyzerTemplate));
|
|
out.write(",\n ");
|
|
out.write(escapeString(message.howToFix));
|
|
out.writeln("); // Generated. Don't edit.");
|
|
}
|
|
});
|
|
|
|
new io.File(outPath).writeAsStringSync(out.toString());
|
|
print("Emitting analyzer done.");
|
|
}
|
|
|
|
/// Translates the shared messages in `../lib/shared_messages.dart` to JSON,
|
|
/// dart2js, and analyzer formats.
|
|
///
|
|
/// Emits the json-output to [jsonPath], the dart2js-output to [dart2jsPath],
|
|
/// and the analyzer-output to [analyzerPath].
|
|
void main() {
|
|
emitJson();
|
|
emitDart2js();
|
|
emitAnalyzer();
|
|
}
|