fromYamlMap static method

ToolConfiguration fromYamlMap(
  1. YamlMap yamlMap,
  2. String canonicalYamlPath,
  3. ResourceProvider resourceProvider
)

Implementation

static ToolConfiguration fromYamlMap(YamlMap yamlMap,
    String canonicalYamlPath, ResourceProvider resourceProvider) {
  var newToolDefinitions = <String, ToolDefinition>{};
  var pathContext = resourceProvider.pathContext;
  for (var MapEntry(:key, value: toolMap) in yamlMap.entries) {
    var name = key.toString();
    if (toolMap is! Map) {
      throw DartdocOptionError(
          'Tools must be defined as a map of tool names to definitions. Tool '
          '$name is not a map.');
    }

    var description = toolMap['description'].toString();

    List<String>? findCommand([String prefix = '']) {
      // If the command key is given, then it applies to all platforms.
      var commandFromKey = toolMap.containsKey('${prefix}command')
          ? '${prefix}command'
          : '$prefix${Platform.operatingSystem}';
      if (!toolMap.containsKey(commandFromKey)) {
        return null;
      }
      var commandFrom = toolMap[commandFromKey] as YamlNode;
      List<String> command;
      if (commandFrom.value is String) {
        command = [commandFrom.toString()];
      } else if (commandFrom is YamlList) {
        command = commandFrom.map((node) => node.toString()).toList();
      } else {
        throw DartdocOptionError(
            'Tool commands must be a path to an executable, or a list of '
            'strings that starts with a path to an executable. The tool '
            "'$name' has a '$commandFromKey' entry that is a "
            '${commandFrom.runtimeType}');
      }
      if (command.isEmpty || command[0].isEmpty) {
        throw DartdocOptionError(
            'Tool commands must not be empty. Tool $name command entry '
            '"$commandFromKey" must contain at least one path.');
      }
      return command;
    }

    var command = findCommand();
    if (command == null) {
      throw DartdocOptionError(
          'At least one of "command" or "${Platform.operatingSystem}" must '
          'be defined for the tool $name.');
    }
    var setupCommand = findCommand('setup_');

    var rawCompileArgs = toolMap[compileArgsTagName];
    var compileArgs = switch (rawCompileArgs) {
      null => const <String>[],
      String() => [toolMap[compileArgsTagName].toString()],
      YamlList() =>
        rawCompileArgs.map((node) => node.toString()).toList(growable: false),
      _ => throw DartdocOptionError(
          'Tool compile arguments must be a list of strings. The tool '
          "'$name' has a '$compileArgsTagName' entry that is a "
          '${rawCompileArgs.runtimeType}',
        ),
    };

    /// Validates [executable] and returns whether it is a Dart script.
    bool isDartScript(String executable) {
      var executableFile = resourceProvider.getFile(executable);
      if (resourceProvider.isNotFound(executableFile)) {
        throw DartdocOptionError('Command executables must exist. '
            'The file "$executable" does not exist for tool $name.');
      }

      var isDartCommand = ToolDefinition.isDartExecutable(executable);
      // Dart scripts don't need to be executable, because they'll be
      // executed with the Dart binary.
      if (!isDartCommand && !resourceProvider.isExecutable(executableFile)) {
        throw DartdocOptionError('Non-Dart commands must be '
            'executable. The file "$executable" for tool $name does not have '
            'execute permission.');
      }
      return isDartCommand;
    }

    var executableRelativePath = command.removeAt(0);
    var executable = pathContext.canonicalize(
        pathContext.join(canonicalYamlPath, executableRelativePath));
    var isDartSetupScript = isDartScript(executable);
    if (setupCommand != null) {
      var setupExecutableRelativePath = setupCommand.removeAt(0);
      var setupExecutable = pathContext.canonicalize(
          pathContext.join(canonicalYamlPath, setupExecutableRelativePath));
      // Setup commands aren't snapshotted, since they're only run once.
      setupCommand = [
        if (isDartSetupScript) Platform.resolvedExecutable,
        setupExecutable,
        ...setupCommand,
      ];
    }
    newToolDefinitions[name] = ToolDefinition.fromCommand(
        [executable, ...command],
        setupCommand ?? const [],
        description,
        resourceProvider,
        compileArgs: compileArgs);
  }
  return ToolConfiguration._(newToolDefinitions, resourceProvider);
}