Нормализовать переводы строк в LF

Решение по TD-STYLE-ANALYZERS: LF — инструменты проекта (Python/Node) пишут LF,
CRLF-.sh не работают на Linux CI (sh scripts/ci.sh), большинство файлов уже были
LF. Добавлен .gitattributes (* text=auto eol=lf, бинарные исключения),
.editorconfig переведён на lf, 1029 файлов конвертированы, git add --renormalize.
Из индекса убраны закравшиеся archive/**/__pycache__/*.pyc.
This commit is contained in:
Rustam Khalimov
2026-09-11 19:01:42 +03:00
parent 39c9bdc1b7
commit 713d554dc2
751 changed files with 94507 additions and 94486 deletions
@@ -1,10 +1,10 @@
using Deal.Modules.Cards.Application.Abstractions;
namespace Deal.Modules.Cards.Application.Dtos;
/// <summary>
/// Результат перехода карточки единым механизмом <see cref="ICardMover"/>.
/// </summary>
/// <param name="Error">Текст 400-ошибки либо null.</param>
/// <param name="Exists">True — карточка найдена и переход выполнен (либо перенос был no-op).</param>
public sealed record CardMoveResultDto(string? Error, bool Exists);
using Deal.Modules.Cards.Application.Abstractions;
namespace Deal.Modules.Cards.Application.Dtos;
/// <summary>
/// Результат перехода карточки единым механизмом <see cref="ICardMover"/>.
/// </summary>
/// <param name="Error">Текст 400-ошибки либо null.</param>
/// <param name="Exists">True — карточка найдена и переход выполнен (либо перенос был no-op).</param>
public sealed record CardMoveResultDto(string? Error, bool Exists);
@@ -1,20 +1,20 @@
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Контакт, извлечённый из источника или указанный вручную.
/// </summary>
public sealed record ContactRef
{
/// <summary>
/// Вид контакта (например, телефон/почта/мессенджер/сайт).
/// </summary>
public string? Kind { get; init; }
public string? Name { get; init; }
public string? Phone { get; init; }
public string? Email { get; init; }
public string? Url { get; init; }
}
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Контакт, извлечённый из источника или указанный вручную.
/// </summary>
public sealed record ContactRef
{
/// <summary>
/// Вид контакта (например, телефон/почта/мессенджер/сайт).
/// </summary>
public string? Kind { get; init; }
public string? Name { get; init; }
public string? Phone { get; init; }
public string? Email { get; init; }
public string? Url { get; init; }
}
@@ -1,48 +1,48 @@
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Ссылка на файл в общем сервисе данных.
/// </summary>
public sealed record DataRef
{
/// <summary>
/// Идентификатор объекта в сервисе данных.
/// </summary>
public required string Id { get; init; }
/// <summary>
/// Ссылка на скачивание/отображение.
/// </summary>
public required string Ref { get; init; }
/// <summary>
/// Тип, определённый сервисом данных (image/video/audio/document/archive/other).
/// </summary>
public string? Kind { get; init; }
public string? MimeType { get; init; }
public string? FileName { get; init; }
public long? Size { get; init; }
public int? Width { get; init; }
public int? Height { get; init; }
public double? DurationSec { get; init; }
/// <summary>
/// Ссылка на превью (если сервис данных сгенерировал).
/// </summary>
public string? PreviewRef { get; init; }
public string? Caption { get; init; }
public int? Order { get; init; }
/// <summary>
/// Прочие метаданные от сервиса данных.
/// </summary>
public IReadOnlyDictionary<string, string>? Meta { get; init; }
}
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Ссылка на файл в общем сервисе данных.
/// </summary>
public sealed record DataRef
{
/// <summary>
/// Идентификатор объекта в сервисе данных.
/// </summary>
public required string Id { get; init; }
/// <summary>
/// Ссылка на скачивание/отображение.
/// </summary>
public required string Ref { get; init; }
/// <summary>
/// Тип, определённый сервисом данных (image/video/audio/document/archive/other).
/// </summary>
public string? Kind { get; init; }
public string? MimeType { get; init; }
public string? FileName { get; init; }
public long? Size { get; init; }
public int? Width { get; init; }
public int? Height { get; init; }
public double? DurationSec { get; init; }
/// <summary>
/// Ссылка на превью (если сервис данных сгенерировал).
/// </summary>
public string? PreviewRef { get; init; }
public string? Caption { get; init; }
public int? Order { get; init; }
/// <summary>
/// Прочие метаданные от сервиса данных.
/// </summary>
public IReadOnlyDictionary<string, string>? Meta { get; init; }
}
@@ -1,20 +1,20 @@
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Загрузка содержимого записи источника по ссылке.
/// </summary>
public interface ISourceContentProvider
{
/// <summary>
/// Вид источника, который обслуживает провайдер.
/// </summary>
public string Kind { get; }
/// <summary>
/// Загружает содержимое записи источника.
/// </summary>
/// <param name="source">Ссылка на источник.</param>
/// <param name="ct">Токен отмены.</param>
/// <returns>Содержимое записи либо null, если источник не отдал данные.</returns>
public Task<SourceContent?> LoadAsync(SourceRef source, CancellationToken ct);
}
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Загрузка содержимого записи источника по ссылке.
/// </summary>
public interface ISourceContentProvider
{
/// <summary>
/// Вид источника, который обслуживает провайдер.
/// </summary>
public string Kind { get; }
/// <summary>
/// Загружает содержимое записи источника.
/// </summary>
/// <param name="source">Ссылка на источник.</param>
/// <param name="ct">Токен отмены.</param>
/// <returns>Содержимое записи либо null, если источник не отдал данные.</returns>
public Task<SourceContent?> LoadAsync(SourceRef source, CancellationToken ct);
}
@@ -1,15 +1,15 @@
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Уведомление о принятой записи источника.
/// </summary>
public interface ISourceIngestObserver
{
/// <summary>
/// Обрабатывает принятую запись источника.
/// </summary>
/// <param name="item">Принятая запись.</param>
/// <param name="ct">Токен отмены.</param>
/// <returns>Завершается после обработки; сбой наблюдателя не влияет на приём.</returns>
public Task OnIngestedAsync(SourceItem item, CancellationToken ct);
}
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Уведомление о принятой записи источника.
/// </summary>
public interface ISourceIngestObserver
{
/// <summary>
/// Обрабатывает принятую запись источника.
/// </summary>
/// <param name="item">Принятая запись.</param>
/// <param name="ct">Токен отмены.</param>
/// <returns>Завершается после обработки; сбой наблюдателя не влияет на приём.</returns>
public Task OnIngestedAsync(SourceItem item, CancellationToken ct);
}
@@ -1,35 +1,35 @@
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Содержимое первичного сообщения источника.
/// </summary>
public sealed record SourceContent
{
public string? Text { get; init; }
/// <summary>
/// Форматированный текст (если источник его предоставил).
/// </summary>
public string? Html { get; init; }
public string? Author { get; init; }
public string? Subject { get; init; }
/// <summary>
/// Вложения: ссылки на файлы в общем сервисе данных.
/// </summary>
public IReadOnlyList<DataRef> Data { get; init; } = [];
/// <summary>
/// Ссылки, не являющиеся файлами.
/// </summary>
public IReadOnlyList<string>? Links { get; init; }
public IReadOnlyList<ContactRef>? Contacts { get; init; }
/// <summary>
/// Прочие поля, не подходящие под текст/файл/ссылку/контакт.
/// </summary>
public IReadOnlyDictionary<string, string>? Extra { get; init; }
}
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Содержимое первичного сообщения источника.
/// </summary>
public sealed record SourceContent
{
public string? Text { get; init; }
/// <summary>
/// Форматированный текст (если источник его предоставил).
/// </summary>
public string? Html { get; init; }
public string? Author { get; init; }
public string? Subject { get; init; }
/// <summary>
/// Вложения: ссылки на файлы в общем сервисе данных.
/// </summary>
public IReadOnlyList<DataRef> Data { get; init; } = [];
/// <summary>
/// Ссылки, не являющиеся файлами.
/// </summary>
public IReadOnlyList<string>? Links { get; init; }
public IReadOnlyList<ContactRef>? Contacts { get; init; }
/// <summary>
/// Прочие поля, не подходящие под текст/файл/ссылку/контакт.
/// </summary>
public IReadOnlyDictionary<string, string>? Extra { get; init; }
}
@@ -1,42 +1,42 @@
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Выбирает провайдера содержимого по виду источника.
/// </summary>
public sealed class SourceContentResolver
{
private readonly Dictionary<string, ISourceContentProvider> _providers;
/// <summary>
/// Создаёт реестр провайдеров содержимого.
/// </summary>
/// <param name="providers">Зарегистрированные провайдеры; последний по виду перекрывает предыдущих.</param>
public SourceContentResolver(IEnumerable<ISourceContentProvider> providers)
{
_providers = new Dictionary<string, ISourceContentProvider>(StringComparer.OrdinalIgnoreCase);
foreach (ISourceContentProvider provider in providers)
{
_providers[provider.Kind] = provider;
}
}
/// <summary>
/// Есть ли провайдер для вида источника.
/// </summary>
/// <param name="source">Ссылка на источник.</param>
/// <returns>true — содержимое можно загрузить лениво.</returns>
public bool CanResolve(SourceRef source) => _providers.ContainsKey(source.Kind);
/// <summary>
/// Загружает содержимое записи источника.
/// </summary>
/// <param name="source">Ссылка на источник.</param>
/// <param name="ct">Токен отмены.</param>
/// <returns>Содержимое записи либо null — провайдера нет/источник не отдал данные.</returns>
public Task<SourceContent?> ResolveAsync(SourceRef source, CancellationToken ct)
{
return _providers.TryGetValue(source.Kind, out ISourceContentProvider? provider)
? provider.LoadAsync(source, ct)
: Task.FromResult<SourceContent?>(null);
}
}
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Выбирает провайдера содержимого по виду источника.
/// </summary>
public sealed class SourceContentResolver
{
private readonly Dictionary<string, ISourceContentProvider> _providers;
/// <summary>
/// Создаёт реестр провайдеров содержимого.
/// </summary>
/// <param name="providers">Зарегистрированные провайдеры; последний по виду перекрывает предыдущих.</param>
public SourceContentResolver(IEnumerable<ISourceContentProvider> providers)
{
_providers = new Dictionary<string, ISourceContentProvider>(StringComparer.OrdinalIgnoreCase);
foreach (ISourceContentProvider provider in providers)
{
_providers[provider.Kind] = provider;
}
}
/// <summary>
/// Есть ли провайдер для вида источника.
/// </summary>
/// <param name="source">Ссылка на источник.</param>
/// <returns>true — содержимое можно загрузить лениво.</returns>
public bool CanResolve(SourceRef source) => _providers.ContainsKey(source.Kind);
/// <summary>
/// Загружает содержимое записи источника.
/// </summary>
/// <param name="source">Ссылка на источник.</param>
/// <param name="ct">Токен отмены.</param>
/// <returns>Содержимое записи либо null — провайдера нет/источник не отдал данные.</returns>
public Task<SourceContent?> ResolveAsync(SourceRef source, CancellationToken ct)
{
return _providers.TryGetValue(source.Kind, out ISourceContentProvider? provider)
? provider.LoadAsync(source, ct)
: Task.FromResult<SourceContent?>(null);
}
}
@@ -1,11 +1,11 @@
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Единый контракт входящей записи: источник + содержимое.
/// </summary>
public sealed record SourceItem
{
public required SourceRef Source { get; init; }
public required SourceContent Content { get; init; }
}
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Единый контракт входящей записи: источник + содержимое.
/// </summary>
public sealed record SourceItem
{
public required SourceRef Source { get; init; }
public required SourceContent Content { get; init; }
}
@@ -1,47 +1,47 @@
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Источник данных: откуда пришла запись.
/// </summary>
public sealed record SourceRef
{
/// <summary>
/// Дискриминатор источника (значение задаёт сервис-владелец).
/// </summary>
public required string Kind { get; init; }
/// <summary>
/// Идентификатор записи в источнике (сообщение/строка/файл).
/// </summary>
public string? ExternalId { get; init; }
/// <summary>
/// Подпись источника для интерфейса.
/// </summary>
public string? DisplayName { get; init; }
/// <summary>
/// Ссылка на оригинал (url, deep-link, путь).
/// </summary>
public string? OriginRef { get; init; }
public string? Author { get; init; }
public DateTimeOffset ReceivedAt { get; init; }
/// <summary>
/// Прочие метаданные источника.
/// </summary>
public IReadOnlyDictionary<string, string>? Extra { get; init; }
}
/// <summary>
/// Дискриминаторы источников, владельцем которых является модуль.
/// </summary>
public static class SourceKinds
{
/// <summary>
/// Запись создана вручную в системе.
/// </summary>
public const string Local = "local";
}
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Источник данных: откуда пришла запись.
/// </summary>
public sealed record SourceRef
{
/// <summary>
/// Дискриминатор источника (значение задаёт сервис-владелец).
/// </summary>
public required string Kind { get; init; }
/// <summary>
/// Идентификатор записи в источнике (сообщение/строка/файл).
/// </summary>
public string? ExternalId { get; init; }
/// <summary>
/// Подпись источника для интерфейса.
/// </summary>
public string? DisplayName { get; init; }
/// <summary>
/// Ссылка на оригинал (url, deep-link, путь).
/// </summary>
public string? OriginRef { get; init; }
public string? Author { get; init; }
public DateTimeOffset ReceivedAt { get; init; }
/// <summary>
/// Прочие метаданные источника.
/// </summary>
public IReadOnlyDictionary<string, string>? Extra { get; init; }
}
/// <summary>
/// Дискриминаторы источников, владельцем которых является модуль.
/// </summary>
public static class SourceKinds
{
/// <summary>
/// Запись создана вручную в системе.
/// </summary>
public const string Local = "local";
}
@@ -1,47 +1,47 @@
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Общие значения и производные поля ссылки на источник.
/// </summary>
public static class SourceRefs
{
/// <summary>
/// Цвет источника по умолчанию.
/// </summary>
public const string DefaultHue = "#666";
/// <summary>
/// Ключ прочих метаданных с цветом источника.
/// </summary>
public const string HueKey = "hue";
/// <summary>
/// Пустая ссылка на источник.
/// </summary>
public static SourceRef Empty { get; } = new() { Kind = string.Empty };
/// <summary>
/// Ключ уникальности записи в источнике: вид + оригинал + внешний id.
/// </summary>
/// <param name="source">Ссылка на источник.</param>
/// <returns>Стабильный ключ для дедупликации.</returns>
public static string DedupeKey(this SourceRef source) =>
string.Concat(source.Kind, "|", source.OriginRef ?? string.Empty, "|", source.ExternalId ?? string.Empty);
/// <summary>
/// Цвет источника для интерфейса.
/// </summary>
/// <param name="source">Ссылка на источник.</param>
/// <returns>Цвет из метаданных либо цвет по умолчанию.</returns>
public static string ResolveHue(this SourceRef source)
{
if (source.Extra is not null
&& source.Extra.TryGetValue(HueKey, out string? hue)
&& !string.IsNullOrWhiteSpace(hue))
{
return hue;
}
return DefaultHue;
}
}
namespace Deal.Modules.Cards.Application.Sources;
/// <summary>
/// Общие значения и производные поля ссылки на источник.
/// </summary>
public static class SourceRefs
{
/// <summary>
/// Цвет источника по умолчанию.
/// </summary>
public const string DefaultHue = "#666";
/// <summary>
/// Ключ прочих метаданных с цветом источника.
/// </summary>
public const string HueKey = "hue";
/// <summary>
/// Пустая ссылка на источник.
/// </summary>
public static SourceRef Empty { get; } = new() { Kind = string.Empty };
/// <summary>
/// Ключ уникальности записи в источнике: вид + оригинал + внешний id.
/// </summary>
/// <param name="source">Ссылка на источник.</param>
/// <returns>Стабильный ключ для дедупликации.</returns>
public static string DedupeKey(this SourceRef source) =>
string.Concat(source.Kind, "|", source.OriginRef ?? string.Empty, "|", source.ExternalId ?? string.Empty);
/// <summary>
/// Цвет источника для интерфейса.
/// </summary>
/// <param name="source">Ссылка на источник.</param>
/// <returns>Цвет из метаданных либо цвет по умолчанию.</returns>
public static string ResolveHue(this SourceRef source)
{
if (source.Extra is not null
&& source.Extra.TryGetValue(HueKey, out string? hue)
&& !string.IsNullOrWhiteSpace(hue))
{
return hue;
}
return DefaultHue;
}
}
@@ -1,18 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\Deal.SharedKernel\Deal.SharedKernel.csproj" />
<ProjectReference Include="..\Deal.Contracts\Deal.Contracts.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.11" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\Deal.SharedKernel\Deal.SharedKernel.csproj" />
<ProjectReference Include="..\Deal.Contracts\Deal.Contracts.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.11" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>