-
Notifications
You must be signed in to change notification settings - Fork 1
docs: заполнить README и javadoc публичного API #83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,124 @@ | ||
| # 1c-syntax utils | ||
| # utils | ||
|
|
||
| Common utils for 1c-syntax team java projects | ||
| [](https://github.com/1c-syntax/utils/actions/workflows/check.yml) | ||
| [](https://central.sonatype.com/artifact/io.github.1c-syntax/utils) | ||
| [](https://github.com/1c-syntax/utils/releases) | ||
| [](https://adoptium.net/) | ||
| [](LICENSE.md) | ||
|
|
||
| Общие утилиты для java-проектов команды [1c-syntax](https://github.com/1c-syntax) — | ||
| небольшие независимые помощники, переиспользуемые в | ||
| [BSL Language Server](https://github.com/1c-syntax/bsl-language-server) и смежных проектах. | ||
|
|
||
| Библиотека сознательно держит минимальную замкнутость зависимостей и помечена | ||
| [JSpecify](https://jspecify.dev/) `@NullMarked` (типы считаются non-null, если не аннотированы | ||
| `@Nullable`). | ||
|
|
||
| ## Требования | ||
|
|
||
| - Java 21 или новее (сборка таргетится на Java 21; CI прогоняется на Java 21 и 25). | ||
|
|
||
| ## Подключение | ||
|
|
||
| Артефакт публикуется в Maven Central под координатами `io.github.1c-syntax:utils`. | ||
|
|
||
| ### Gradle (Kotlin DSL) | ||
|
|
||
| ```kotlin | ||
| dependencies { | ||
| implementation("io.github.1c-syntax:utils:VERSION") | ||
| } | ||
| ``` | ||
|
|
||
| ### Maven | ||
|
|
||
| ```xml | ||
| <dependency> | ||
| <groupId>io.github.1c-syntax</groupId> | ||
| <artifactId>utils</artifactId> | ||
| <version>VERSION</version> | ||
| </dependency> | ||
| ``` | ||
|
|
||
| Актуальную версию смотрите в | ||
| [релизах](https://github.com/1c-syntax/utils/releases) или на | ||
| [Maven Central](https://central.sonatype.com/artifact/io.github.1c-syntax/utils). | ||
|
|
||
| ## Что внутри | ||
|
|
||
| ### Пакет `com.github._1c_syntax.utils` | ||
|
|
||
| | Класс | Назначение | | ||
| | --- | --- | | ||
| | `Absolute` | Приведение файловых путей и URI к каноническому абсолютному виду — стабильный ключ для одного и того же файла независимо от формы записи. | | ||
| | `Lazy<T>` | Потокобезопасное хранилище значения с ленивым однократным вычислением (double-checked locking) и возможностью сброса кэша. | | ||
| | `GenericInterner<T>` | Потокобезопасный интернер значений: один канонический экземпляр на класс эквивалентности — экономия памяти и сравнение по ссылке. | | ||
| | `StringInterner` | Интернер строк на базе `GenericInterner`, дополнительно нормализующий `null` в пустую строку. | | ||
| | `CaseInsensitivePattern` | Компиляция регулярных выражений без учёта регистра с поддержкой Unicode (важно для кириллицы кода 1С). | | ||
|
|
||
| ### Пакет `com.github._1c_syntax.utils.downloader` | ||
|
|
||
| Загрузчик исполняемого файла [BSL Language Server](https://github.com/1c-syntax/bsl-language-server) | ||
| из GitHub-релизов (для встраивания в IDE-плагины и другие клиенты). | ||
|
|
||
| | Класс | Назначение | | ||
| | --- | --- | | ||
| | `BslLanguageServerDownloader` | Скачивает подходящий под ОС ассет последнего релиза, распаковывает его и отдаёт путь к бинарю; кэширует установленную версию и опрашивает GitHub не чаще заданного интервала. | | ||
| | `GitHubReleaseClient` | Находит последний релиз выбранного канала через GitHub REST API (на `java.net.http.HttpClient` + gson, без клиентских библиотек GitHub). | | ||
| | `BslLanguageServerReleaseChannel` | Канал релизов: `STABLE` или `PRERELEASE`. | | ||
| | `DownloadProgressListener` | Слушатель прогресса скачивания ассета. | | ||
|
|
||
| ## Примеры использования | ||
|
|
||
| Каноникализация пути и URI: | ||
|
|
||
| ```java | ||
| Path path = Absolute.path("./src/../build/out.txt"); // абсолютный канонический путь | ||
| URI uri = Absolute.uri("file:///C:/Program%20Files/app"); // нормализованный file:-URI | ||
| ``` | ||
|
|
||
| Ленивое вычисление: | ||
|
|
||
| ```java | ||
| Lazy<List<String>> lines = new Lazy<>(() -> readAllLines(file)); | ||
| List<String> value = lines.getOrCompute(); // вычислится один раз и закэшируется | ||
| lines.clear(); // сбросить кэш | ||
| ``` | ||
|
|
||
| Интернирование: | ||
|
|
||
| ```java | ||
| StringInterner interner = new StringInterner(); | ||
| String canonical = interner.intern(name); // равные строки делят один экземпляр | ||
| ``` | ||
|
|
||
| Регистронезависимый поиск с учётом Unicode: | ||
|
|
||
| ```java | ||
| Pattern pattern = CaseInsensitivePattern.compile("Процедура"); | ||
| boolean matches = pattern.matcher("процедура").matches(); // true | ||
| ``` | ||
|
|
||
| Скачивание BSL Language Server: | ||
|
|
||
| ```java | ||
| var client = new GitHubReleaseClient(githubToken); // токен может быть null | ||
| var downloader = new BslLanguageServerDownloader(installDir, client, HttpClient.newHttpClient()); | ||
| Path binary = downloader.downloadIfNeeded(BslLanguageServerReleaseChannel.STABLE); | ||
| ``` | ||
|
|
||
| ## Сборка | ||
|
|
||
| Используйте wrapper Gradle: | ||
|
|
||
| ```bash | ||
| ./gradlew build # сборка, проверки и тесты | ||
| ./gradlew check # то, что гоняет CI (test + jacoco + javadoc + проверка лицензий) | ||
| ``` | ||
|
|
||
| Заголовки лицензии проверяются плагином license; при необходимости их можно проставить командой | ||
| `./gradlew licenseFormat`. | ||
|
|
||
| ## Лицензия | ||
|
|
||
| [GNU LGPL 3.0 или новее](LICENSE.md) (`SPDX-License-Identifier: LGPL-3.0-or-later`). | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,20 +34,33 @@ | |
| import java.nio.file.Path; | ||
|
|
||
| /** | ||
| * Методы получения абсолютного пути файла с учетом различных особенностей | ||
| * Приведение файловых путей и URI к каноническому абсолютному виду. | ||
| * | ||
| * <p>Утилита сглаживает различия в записи одного и того же файла, из-за которых он иначе выглядел | ||
| * бы как разные ресурсы: относительные пути разворачиваются в абсолютные, символические ссылки и | ||
| * сегменты {@code .}/{@code ..} схлопываются через каноникализацию файла, регистр и разделители | ||
| * приводятся к виду файловой системы. Для {@code file:}-URI дополнительно нормализуется | ||
| * процентное кодирование спецсимволов и восстанавливается authority, чтобы форма URI совпадала с | ||
| * той, что отдаёт JDK для канонического файла. | ||
| * | ||
| * <p>Благодаря этому URI/путь можно использовать как стабильный ключ (например, документа в | ||
| * рабочей области), не опасаясь, что тот же файл придёт в другой записи. | ||
| */ | ||
| @UtilityClass | ||
| public final class Absolute { | ||
|
|
||
| /** | ||
| * Получение URI из строки | ||
| * Разбирает строковый URI и приводит его к каноническому абсолютному виду. | ||
| * | ||
| * <p>Если строка не является корректным URL, она интерпретируется как {@link URI} и обрабатывается | ||
| * через {@link #uri(URI)}. | ||
| * | ||
| * @param uri - строковое представление URI | ||
| * @return - полученное значение | ||
| * @param uri строковое представление URI | ||
| * @return канонический абсолютный URI | ||
|
Comment on lines
+37
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
rg -n -C3 'Absolute\.(uri|path)\(' src/main/java src/test/javaRepository: 1c-syntax/utils Length of output: 13624 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
# Map and inspect the Absolute utility implementation around doc and methods, and relevant tests.
ast-grep outline src/main/java/com/github/_1c_syntax/utils/Absolute.java || true
printf '\n--- Absolute.java relevant sections ---\n'
sed -n '1,180p' src/main/java/com/github/_1c_syntax/utils/Absolute.java | cat -n
printf '\n--- AbsoluteTest.java relevant URI behavior tests ---\n'
sed -n '1,230p' src/test/java/com/github/_1c_syntax/utils/AbsoluteTest.java | cat -nRepository: 1c-syntax/utils Length of output: 14168 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
# Probe JDK URI semantics and Absolute helper behavior using only repository source and runtime types
# without running repository project code.
python3 - <<'PY'
from pathlib import Path
p = Path("src/main/java/com/github/_1c_syntax/utils/Absolute.java")
text = p.read_text()
print("contains normalize() call:", "normalize()" in text or "URI.normalize" in text)
print("handles query/fragment explicitly:", any(name in text for name in ("getQuery", "getFragment", "getSchemeSpecificPart", "new URI(")))
PY
# Run focused Java probe in memory for JDK URI behavior and Path.of(URI)/File normalization as strings.
# No repository files are imported or executed; only JDK classes are used.
javac -d /tmp/jdk-uri-probe - <<'JAVA'
import java.net.*;
import java.io.*;
public class UriProbe {
public static void main(String[] args) throws Exception {
String[] inputs = {
"file:///fake?query#frag",
"file:///a/./b/../fake.txt",
"untitled://server/x?query#frag"
};
for (String s : inputs) {
URI u = new URI(s);
String psp = u.getSchemeSpecificPart();
String path = u.getPath();
URI normalized = u.normalize();
System.out.println("INPUT=" + s);
System.out.println(" scheme=" + u.getScheme()
+ " schemeSpecificPart=" + psp
+ " path=" + path
+ " query=" + u.getQuery()
+ " fragment=" + u.getFragment()
+ " normalizedPath=" + normalized.getPath());
}
File f = new File(new URI("file:///C%3A/a/../b?query#frag"));
System.out.println("FILE_URI_TO_FILE=" + f.toString());
}
}
JAVA
java -cp /tmp/jdk-uri-probe UriProbeRepository: 1c-syntax/utils Length of output: 329 Не описывайте Метод кодирует полный 🤖 Prompt for AI Agents |
||
| */ | ||
| public static URI uri(String uri) { | ||
| try { | ||
| var url = new URL(uri.replace("+", "%2B").replace("%%", "%25%")); | ||
|
Check warning on line 63 in src/main/java/com/github/_1c_syntax/utils/Absolute.java
|
||
| var decodedPath = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8); | ||
| var decodedUri = new URI( | ||
| url.getProtocol(), | ||
|
|
@@ -66,10 +79,11 @@ | |
| } | ||
|
|
||
| /** | ||
| * Получение абсолютного URI из URI с валидацией | ||
| * Приводит URI к каноническому абсолютному виду, нормализуя процентное кодирование пути и, | ||
| * для {@code file:}-URI без authority, восстанавливая её через каноникализацию файла. | ||
| * | ||
| * @param uri - исходный URI | ||
| * @return - полученное значение | ||
| * @param uri исходный URI | ||
| * @return канонический абсолютный URI | ||
| */ | ||
| public static URI uri(URI uri) { | ||
| var decodedUri = URI.create(uri.getScheme() + ":" + encodePath(uri.getSchemeSpecificPart())); | ||
|
|
@@ -78,50 +92,51 @@ | |
| } | ||
|
|
||
| /** | ||
| * Получение URI файла | ||
| * Возвращает канонический абсолютный URI файла. | ||
| * | ||
| * @param file - исходный файл | ||
| * @return - полученное значение | ||
| * @param file исходный файл | ||
| * @return канонический абсолютный {@code file:}-URI | ||
| */ | ||
| public static URI uri(File file) { | ||
| return uri(path(file).toUri()); | ||
| } | ||
|
|
||
| /** | ||
| * Получение пути (path) из строки | ||
| * Возвращает канонический абсолютный путь по его строковому представлению. | ||
| * | ||
| * @param path - строковое представление пути | ||
| * @return - полученное значение | ||
| * @param path строковое представление пути | ||
| * @return канонический абсолютный путь | ||
| */ | ||
| public static Path path(String path) { | ||
| return path(Path.of(path)); | ||
| } | ||
|
|
||
| /** | ||
| * Получение пути (path) из URI | ||
| * Возвращает канонический абсолютный путь к файлу, на который указывает URI. | ||
| * | ||
| * @param uri - исходное значение URI | ||
| * @return - полученное значение | ||
| * @param uri исходный URI | ||
| * @return канонический абсолютный путь | ||
| */ | ||
| public static Path path(URI uri) { | ||
| return path(Path.of(uri(uri))); | ||
|
Comment on lines
114
to
121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
rg -n -C3 'path\(URI uri\)|Path\.of\(uri' src/main/java src/test/javaRepository: 1c-syntax/utils Length of output: 794 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
echo "== Candidate files =="
fd -a 'Absolute\.java$' . | sed 's#^\./##'
echo "== Absolute.java relevant sections =="
sed -n '1,170p' src/main/java/com/github/_1c_syntax/utils/Absolute.java
echo "== References to Absolute.path =="
rg -n -C3 'Absolute\.path|\.path\(Path\.(of)?\(|path\(' src/main/java src/test/java | sed -n '1,200p'
echo "== Java Path.of URI documentation excerpt =="
python3 - <<'PY'
# Programmatic source-level check: show source string for Path.of(String) and Uri pattern requirements.
print("Javadoc/source context is not available from repository; rely on Java API contract.")
PYRepository: 1c-syntax/utils Length of output: 12087 🌐 Web query:
💡 Result: The Path.of(URI) method in Java throws an IllegalArgumentException if the provided URI does not meet specific requirements associated with the available file system providers [1][2]. The method works by iterating over all installed FileSystemProviders to locate one that matches the URI's scheme [1][3]. If a suitable provider is found, it is then tasked with converting the URI into a Path [1][2]. For the default file system provider, which handles the "file" URI scheme, the following preconditions must be met [1][4]: 1. The URI must have a non-empty path component [1][5]. 2. The URI must have undefined query and fragment components [1][2]. If the URI scheme is not recognized (i.e., no installed provider supports it), or if the URI fails to meet the specific requirements of the chosen provider (such as the default provider's requirement for a non-empty path and absence of query/fragment components), an IllegalArgumentException is thrown [1][6][4]. Additionally, if a URI has no scheme at all, the method will fail because the scheme is required to identify the correct provider [7]. Citations:
Укажите схему
🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| /** | ||
| * Получение абсолютного пути (path) из Path | ||
| * Возвращает канонический абсолютный путь для переданного {@link Path}. | ||
| * | ||
| * @param path - исходное значение пути | ||
| * @return - полученное значение | ||
| * @param path исходный путь | ||
| * @return канонический абсолютный путь | ||
| */ | ||
| public static Path path(Path path) { | ||
| return path(path.toFile()); | ||
| } | ||
|
|
||
| /** | ||
| * Получение пути файла | ||
| * Возвращает канонический абсолютный путь файла: разворачивает символические ссылки и | ||
| * сегменты {@code .}/{@code ..}, приводит запись к виду файловой системы. | ||
| * | ||
| * @param file - исходный файл | ||
| * @return - полученное значение | ||
| * @param file исходный файл | ||
| * @return канонический абсолютный путь | ||
| */ | ||
| @SneakyThrows | ||
| public static Path path(File file) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: 1c-syntax/utils
Length of output: 1830
🏁 Script executed:
Repository: 1c-syntax/utils
Length of output: 2397
Синхронизируйте вариант лицензии в README и Maven-метаданных.
Раздел лицензии и бейдж README заявляют
LGPL-3.0-or-later, аbuild.gradle.kts:135-147публикует в POMGNU LGPL 3с URL фиксированной LGPL 3.0. Выберите намеренный вариант и обновите соответствующие README, POM/заголовки исходников, чтобы публикация не противоречила опубликованному лицензированию.🤖 Prompt for AI Agents