// Copyright (c) 2021, 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.

/// This file contains code to generate scanner and parser message
/// based on the information in pkg/front_end/messages.yaml.
///
/// For each message in messages.yaml that contains an 'index:' field,
/// this tool generates an error with the name specified by the 'analyzerCode:'
/// field and an entry in the fastaAnalyzerErrorList for that generated error.
/// The text in the 'analyzerCode:' field must contain the name of the class
/// containing the error and the name of the error separated by a `.`
/// (e.g. ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND).
///
/// It is expected that 'dart pkg/front_end/tool/generate_messages.dart'
/// has already been successfully run.
library;

import 'dart:convert';

import 'package:analyzer_testing/package_root.dart' as pkg_root;
import 'package:analyzer_utilities/analyzer_messages.dart';
import 'package:analyzer_utilities/located_error.dart';
import 'package:analyzer_utilities/messages.dart';
import 'package:analyzer_utilities/tools.dart';

Future<void> main() async {
  await GeneratedContent.generateAll(pkg_root.packageRoot, allTargets);
}

/// A list of all targets generated by this code generator.
final List<GeneratedContent> allTargets = _analyzerGeneratedFiles();

/// Generates a list of [GeneratedContent] objects describing all the analyzer
/// files that need to be generated.
List<GeneratedContent> _analyzerGeneratedFiles() {
  return [
    GeneratedFile('analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart', (
      pkgRoot,
    ) async {
      var codeGenerator = _DiagnosticCodeValuesGenerator();
      codeGenerator.generate();
      return codeGenerator.out.toString();
    }),
    for (var package in AnalyzerDiagnosticPackage.values)
      GeneratedFile(
        '${package.dirName}/lib/${package.diagnosticPathPart}.g.dart',
        (pkgRoot) async {
          var codeGenerator = _AnalyzerDiagnosticGenerator(
            package: package,
            parentLibrary:
                'package:${package.dirName}/${package.diagnosticPathPart}.dart',
          );
          codeGenerator.generate();
          return codeGenerator.out.toString();
        },
      ),
  ];
}

/// Code generator for files containing analyzer diagnostics as top level
/// constants.
class _AnalyzerDiagnosticGenerator {
  /// The package into which diagnostic will be generated.
  final AnalyzerDiagnosticPackage package;

  /// The Uri of the library that the generated file will be a part of.
  final String parentLibrary;

  final StringBuffer out = StringBuffer('''
// Copyright (c) 2025, 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.

// THIS FILE IS GENERATED. DO NOT EDIT.
//
// Instead modify 'pkg/analyzer/messages.yaml' and run
// 'dart run pkg/analyzer/tool/messages/generate.dart' to update.
''');

  _AnalyzerDiagnosticGenerator({
    required this.package,
    required this.parentLibrary,
  });

  void generate() {
    package.writeIgnoresTo(out);
    out.writeln();
    out.write('''
part of ${json.encode(parentLibrary)};
''');
    out.writeln();

    var memberAccumulator = MemberAccumulator();

    for (var message in diagnosticTables.activeMessagesByPackage[package]!) {
      LocatedError.wrap(span: message.keySpan, () {
        message.toAnalyzerCode(memberAccumulator: memberAccumulator);
      });
    }

    memberAccumulator.writeTo(out);
  }
}

class _DiagnosticCodeValuesGenerator {
  final StringBuffer out = StringBuffer('''
// 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.

// THIS FILE IS GENERATED. DO NOT EDIT.
//
// Instead modify 'pkg/analyzer/messages.yaml' and run
// 'dart run pkg/analyzer/tool/messages/generate.dart' to update.
''');

  void generate() {
    AnalyzerDiagnosticPackage.analyzer.writeIgnoresTo(out);
    out.writeln();
    out.writeln(r'''
part of 'diagnostic_code_values.dart';
''');
    out.writeln();
    out.writeln(
      "@AnalyzerPublicApi(message: 'exported by lib/error/error.dart')",
    );
    out.writeln('const List<DiagnosticCode> diagnosticCodeValues = [');
    for (var message
        in diagnosticTables.activeMessagesByPackage[AnalyzerDiagnosticPackage
            .analyzer]!) {
      out.writeln('  ${message.analyzerCode.analyzerCodeReference},');
    }
    out.writeln('];');
    out.writeln();
    _generateSharedAnalyzerCodeList();
    out.writeln(
      "@AnalyzerPublicApi(message: 'exported by lib/error/error.dart')",
    );
    out.writeln('@Deprecated("Use \'diagnosticCodeValues\' instead")');
    out.writeln(
      'List<DiagnosticCode> get errorCodeValues => diagnosticCodeValues;',
    );
  }

  void _generateSharedAnalyzerCodeList() {
    out.writeln('final sharedAnalyzerCodes = <DiagnosticCode>[');
    for (var entry in diagnosticTables.sortedSharedDiagnostics) {
      out.writeln('${entry.analyzerCode.analyzerCodeReference},');
    }
    out.writeln('];');
  }
}
