blob: a20227ac59e060ca4b5438940df7b2a3c5ab3f90 [file] [log] [blame]
// 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);
}
}