|
| 1 | +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file |
| 2 | +// for details. All rights reserved. Use of this source code is governed by a |
| 3 | +// BSD-style license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +/// This is a temporary utility script that modifies error codes in |
| 6 | +/// `messages.yaml` files, changing analyzer error codes from UPPER_SNAKE_CASE |
| 7 | +/// to camelCase. |
| 8 | +library; |
| 9 | + |
| 10 | +import 'dart:io'; |
| 11 | + |
| 12 | +import 'package:analyzer_plugin/protocol/protocol_common.dart'; |
| 13 | +import 'package:analyzer_utilities/analyzer_messages.dart'; |
| 14 | +import 'package:analyzer_utilities/extensions/string.dart'; |
| 15 | +import 'package:analyzer_utilities/lint_messages.dart'; |
| 16 | +import 'package:analyzer_utilities/messages.dart'; |
| 17 | +import 'package:collection/collection.dart'; |
| 18 | +import 'package:source_span/source_span.dart'; |
| 19 | +import 'package:yaml/yaml.dart'; |
| 20 | + |
| 21 | +void main() { |
| 22 | + Map<Uri, Converter> converters = {}; |
| 23 | + for (var message in [ |
| 24 | + ...analyzerMessages, |
| 25 | + ...analysisServerMessages, |
| 26 | + ...feAnalyzerSharedMessages, |
| 27 | + ...lintMessages, |
| 28 | + ...frontEndMessages, |
| 29 | + ]) { |
| 30 | + var sourceUrl = message.keySpan.sourceUrl; |
| 31 | + (converters[sourceUrl!] ??= Converter( |
| 32 | + File(sourceUrl.toFilePath()), |
| 33 | + )).convertMessage(message); |
| 34 | + } |
| 35 | + for (var converter in converters.values) { |
| 36 | + converter.apply(); |
| 37 | + } |
| 38 | +} |
| 39 | + |
| 40 | +class Converter { |
| 41 | + final File file; |
| 42 | + late final isAnalyzerFormat = switch (Uri.file(file.path).pathSegments) { |
| 43 | + [..., '_fe_analyzer_shared', 'messages.yaml'] => false, |
| 44 | + [..., 'analyzer', 'messages.yaml'] => true, |
| 45 | + [..., 'analysis_server', 'messages.yaml'] => true, |
| 46 | + [..., 'linter', 'messages.yaml'] => true, |
| 47 | + _ => throw 'Unexpected path ${file.path}', |
| 48 | + }; |
| 49 | + late final String content = file.readAsStringSync(); |
| 50 | + late final yaml = loadYamlNode(content) as YamlMap; |
| 51 | + late final messageMaps = isAnalyzerFormat ? yaml.nodes.values : [yaml]; |
| 52 | + late final Map<String, YamlMap> messageNodesByName = { |
| 53 | + for (var messageMap in messageMaps) |
| 54 | + for (var MapEntry(:key, :value) in (messageMap as YamlMap).nodes.entries) |
| 55 | + (key as YamlScalar).value as String: value as YamlMap, |
| 56 | + }; |
| 57 | + final List<SourceEdit> edits = []; |
| 58 | + |
| 59 | + Converter(this.file); |
| 60 | + |
| 61 | + void apply() { |
| 62 | + edits.sortBy((e) => -e.offset); |
| 63 | + file.writeAsStringSync(SourceEdit.applySequence(content, edits)); |
| 64 | + } |
| 65 | + |
| 66 | + void convertMessage(Message message) { |
| 67 | + if (message is AnalyzerMessage && !message.keyString.isCamelCase) { |
| 68 | + _edit(message.keySpan, message.keyString.toCamelCase()); |
| 69 | + } else if (message is CfeStyleMessage) { |
| 70 | + _edit(message.keySpan, message.keyString.toSnakeCase().toCamelCase()); |
| 71 | + } |
| 72 | + if (message is SharedMessage) { |
| 73 | + var messageNode = yaml.nodes[message.keyString] as YamlMap; |
| 74 | + _edit( |
| 75 | + messageNode.nodes['analyzerCode']!.span, |
| 76 | + message.analyzerCode.camelCaseName, |
| 77 | + ); |
| 78 | + } |
| 79 | + if (message.sharedName case var sharedName?) { |
| 80 | + var messageNode = messageNodesByName[message.keyString] as YamlMap; |
| 81 | + _edit(messageNode.nodes['sharedName']!.span, sharedName.camelCaseName); |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + void _edit(SourceSpan span, String newText) { |
| 86 | + edits.add(SourceEdit(span.start.offset, span.length, newText)); |
| 87 | + } |
| 88 | +} |
0 commit comments