| // 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. |
| |
| import 'dart:convert'; |
| |
| import 'package:dart_style/dart_style.dart'; |
| import 'package:path/path.dart' as p; |
| import 'package:pub_semver/pub_semver.dart'; |
| import 'package:yaml/yaml.dart'; |
| |
| import 'util.dart'; |
| |
| class FunctionConfig { |
| /// The number of variable arguments |
| final int? varArgs; |
| |
| const FunctionConfig({this.varArgs}); |
| } |
| |
| abstract interface class Config { |
| /// The name for the configuration |
| String? get name; |
| |
| /// The description for the configuration |
| String? get description; |
| |
| /// Preamble to add at the top of generated code |
| String? get preamble; |
| |
| /// The input files |
| List<String> get input; |
| |
| /// The output file or directory to write bindings to |
| String get output; |
| |
| /// The configuration file |
| Uri? get filename; |
| |
| /// The Dart Language Version to use |
| Version get languageVersion; |
| |
| /// Function configuration |
| FunctionConfig? get functions; |
| |
| bool get singleFileOutput => input.length == 1; |
| |
| /// Include the following declarations when generating JS interop code |
| /// |
| /// This could be a plain name for a declaration, or a [RegExp] pattern |
| /// If empty, all declarations will be generated by default |
| List<String> get includedDeclarations; |
| |
| /// An object consisting of TS Configurations from a tsconfig.json file |
| /// used for configuring the TypeScript Program/Compiler |
| Map<String, dynamic>? get tsConfig; |
| |
| /// The TS Configuration file (tsconfig.json) if any |
| String? get tsConfigFile; |
| |
| /// Whether to ignore source code warnings and errors |
| /// (they will still be printed) |
| bool get ignoreErrors; |
| |
| /// Whether to generate code for all declarations, including non-exported |
| /// declarations |
| bool get generateAll; |
| |
| factory Config( |
| {required List<String> input, |
| required String output, |
| required Version languageVersion, |
| FunctionConfig? functions, |
| Map<String, dynamic>? tsConfig, |
| List<String> includedDeclarations, |
| bool generateAll, |
| bool ignoreErrors, |
| String? tsConfigFile}) = ConfigImpl._; |
| } |
| |
| class ConfigImpl implements Config { |
| @override |
| String? description; |
| |
| @override |
| Uri? filename; |
| |
| @override |
| List<String> input; |
| |
| @override |
| String? name; |
| |
| @override |
| String output; |
| |
| @override |
| Version languageVersion; |
| |
| @override |
| String? preamble; |
| |
| @override |
| FunctionConfig? functions; |
| |
| @override |
| List<String> includedDeclarations; |
| |
| @override |
| Map<String, dynamic>? tsConfig; |
| |
| @override |
| String? tsConfigFile; |
| |
| @override |
| bool ignoreErrors; |
| |
| @override |
| bool generateAll; |
| |
| ConfigImpl._( |
| {required this.input, |
| required this.output, |
| required this.languageVersion, |
| this.functions, |
| this.tsConfig, |
| this.includedDeclarations = const [], |
| this.ignoreErrors = false, |
| this.generateAll = false, |
| this.tsConfigFile}); |
| |
| @override |
| bool get singleFileOutput => input.length == 1; |
| } |
| |
| class YamlConfig implements Config { |
| @override |
| Uri filename; |
| |
| @override |
| List<String> input; |
| |
| @override |
| String? description; |
| |
| @override |
| String? name; |
| |
| @override |
| String output; |
| |
| @override |
| bool get singleFileOutput => input.length == 1; |
| |
| @override |
| Version languageVersion; |
| |
| @override |
| String? preamble; |
| |
| @override |
| FunctionConfig? functions; |
| |
| @override |
| List<String> includedDeclarations; |
| |
| @override |
| Map<String, dynamic>? tsConfig; |
| |
| @override |
| String? tsConfigFile; |
| |
| @override |
| bool ignoreErrors; |
| |
| @override |
| bool generateAll; |
| |
| YamlConfig._( |
| {required this.filename, |
| required this.input, |
| required this.output, |
| this.description, |
| this.name, |
| this.preamble, |
| this.functions, |
| this.includedDeclarations = const [], |
| this.tsConfig, |
| this.tsConfigFile, |
| String? languageVersion, |
| this.ignoreErrors = false, |
| this.generateAll = false}) |
| : languageVersion = languageVersion == null |
| ? DartFormatter.latestLanguageVersion |
| : Version.parse(languageVersion); |
| |
| factory YamlConfig.fromYaml(YamlMap yaml, |
| {required String filename, List<String>? input, String? output}) { |
| List<String> inputFiles; |
| final yamlInput = yaml['input']; |
| if (yamlInput is YamlList) { |
| inputFiles = |
| yamlInput.map((y) => y is String ? y : y.toString()).toList(); |
| } else if (yamlInput is String) { |
| inputFiles = [yamlInput]; |
| } else if (input != null) { |
| inputFiles = input; |
| } else { |
| throw TypeError(); |
| } |
| |
| final allFiles = |
| expandGlobs(inputFiles, extension: '.d.ts', cwd: p.dirname(filename)); |
| |
| final tsConfig = yaml['ts_config'] as YamlMap?; |
| |
| return YamlConfig._( |
| filename: Uri.file(filename), |
| input: |
| allFiles.map((file) => p.join(p.dirname(filename), file)).toList(), |
| output: |
| p.join(p.dirname(filename), (yaml['output'] ?? output) as String), |
| name: yaml['name'] as String?, |
| description: yaml['description'] as String?, |
| languageVersion: yaml['language_version'] as String?, |
| preamble: yaml['preamble'] as String?, |
| tsConfig: tsConfig != null |
| ? jsonDecode(jsonEncode(tsConfig)) as Map<String, dynamic> |
| : null, |
| tsConfigFile: yaml['ts_config_file'] as String?, |
| functions: FunctionConfig( |
| varArgs: (yaml['functions'] as YamlMap?)?['varargs'] as int?), |
| includedDeclarations: (yaml['include'] as YamlList?) |
| ?.map<String>((node) => node.toString()) |
| .toList() ?? |
| [], |
| ignoreErrors: yaml['ignore_errors'] as bool? ?? false, |
| generateAll: yaml['generate_all'] as bool? ?? false); |
| } |
| } |