Инструкции для Claude Code по работе с этим репозиторием: что это за проект, его архитектура, и правила сборки/тестов/оформления. Это краткая карта со ссылками на первоисточники, а не их копия.
Если обнаружишь расхождение между написанным здесь и реальным состоянием репозитория
(другие команды, изменилась структура/версии/процесс) — не молчи: сообщи пользователю о
несоответствии и предложи обновить соответствующий CLAUDE.md (корневой или вложенный).
Применяй правку только с согласия пользователя. То же касается вложенных CLAUDE.md в подкаталогах.
BSL Language Server — реализация LSP для языка 1С:Предприятие 8 (BSL) и OneScript. Консольное Java-приложение на Spring Boot. Главная ценность — движок диагностик (150+ правил статического анализа кода 1С).
Режимы работы (подкоманды): lsp (по умолчанию, stdin/stdout) · analyze (пакетный анализ для CI,
отчёты SARIF/Generic/JSON) · format (форматтер) · websocket · mcp (Model Context Protocol;
stdio/SSE/Streamable HTTP, либо флагом --mcp рядом с lsp/websocket) · version.
Ссылки: сайт · DeepWiki — машинный обзор архитектуры (проверяй по коду) · docs/index.md (ru) · docs/en/index.md (en) · руководство контрибьютора.
- Java, компиляция таргетится на Java 21 (
targetCompatibility = VERSION_21), поэтому и минимальный рантайм — 21: байт-код версии 65 более старая JVM не загрузит. CI собирает и гоняет тесты на 21 и 25, на трёх ОС. - Gradle 9.6 (wrapper, Kotlin DSL —
build.gradle.kts); Spring Boot 4 (DI, кэш, websocket, MCP). - Парсер
bsl-parser(ANTLR4, грамматики BSL и SDBL-запросов); метаданные 1С —mdclasses; LSP — Eclipse LSP4J. - Кэш Caffeine + EhCache · NLP JLanguageTool (ru/en) · AspectJ (AOP) · Lombok · JSpecify · picocli (CLI).
Точка входа — MainApplication (picocli; по подкоманде поднимает Spring-контекст, делегирует в cli/).
Ключевые абстракции (пакет com.github._1c_syntax.bsl.languageserver):
ServerContext/ServerContextProvider(context/) — рабочая область: коллекция документов + метаданные конфигурации 1С.DocumentContext(context/) — состояние одного файла: AST, токены, диагностики, метрики. Тяжёлые вычисления ленивые и кэшируются.DocumentChangeExecutorприменяет инкрементальныеdidChange.BSLLanguageServer/BSLTextDocumentService/BSLWorkspaceService— реализация LSP4J, маршрутизация.- Провайдеры (
providers/) — возможности LSP: hover, definition, references, rename, code actions, formatting, semantic tokens, inlay hints, code lens, folding и т.д.DiagnosticProviderподдерживает обе модели публикации — push (publishDiagnostics) и pull (textDocument/diagnostic). - Диагностики (
diagnostics/) — правила анализа (наследникиAbstractDiagnostic, аннотация@DiagnosticMetadata). - Индекс ссылок (
references/) · символы (context/symbol/) · CFG (cfg/) · конфигурация (configuration/) · отчёты (reporters/). index/— общая основа индексов-кэшей, разрезанных по документам:AbstractDocumentLifecycleClearableIndexсбрасывает записи по событиям жизненного цикла документа. Сами индексы живут в пакетах своих подсистем.
Точки входа подкоманд — в cli/ (каждый класс реализует picocli-Callable<Integer> с аннотацией
@Command и именуется с суффиксом Command: LanguageServerStartCommand, AnalyzeCommand,
FormatCommand, McpCommand, WebsocketCommand, VersionCommand); MainApplication выбирает по подкоманде.
Ключевые подсистемы снабжены вложенными CLAUDE.md (подгружаются при работе с их файлами):
context/ (контекст, символы, AOP) ·
types/ (система типов) ·
references/ ·
diagnostics/ ·
providers/ ·
configuration/ ·
reporters/ ·
cfg/ ·
mcp/ ·
utils/.
- Spring DI и скоупы бинов. Различай три уровня: синглтоны приложения
(
ServerContextProvider,GlobalLanguageServerConfiguration, LSP-сервисы);@WorkspaceScope— по одному экземпляру на каждый workspace (ServerContext,ReferenceIndex,TypeRegistry,DiagnosticInfos, индексы типов, per-workspace конфиг и executor'ы); prototype —DocumentContext(по экземпляру на документ). - Multi-workspace.
ServerContextProviderдержитURI → ServerContext(по папке workspace) и индекс документов для O(1) поиска. «Текущий» workspace выбирается через thread-localWorkspaceContextHolder(а не передаётся параметром); CGLIB-прокси workspace-бина резолвит нужный экземпляр черезWorkspaceBeanScopeпо этому URI. Контекст пробрасывается в пулы потоков через MicrometerThreadLocalAccessor— поэтомуparallelStream()видит правильный workspace. - Событийная модель. Подсистемы общаются через Spring
ApplicationEvent(context/events/,configuration/events/):ServerContextDocumentAdded/Removed/Closed/ClearedEvent,DocumentContextContentChangedEvent,ServerContextPopulatedEvent,ConfigurationTypesRegisteredEvent,*ConfigurationChangedEvent, события workspace и др. События публикуются не вручную, а через AOP (aop/EventPublisherAspect, AspectJ compile-time weaving) при вызовах методов-мутаторов контекста. Downstream-индексы (ReferenceIndex,TypeRegistry, провайдеры) слушают их через@EventListenerи инвалидируют кэши. Правило: меняешь модель/добавляешь вид изменения данных — убедись, что публикуется нужное событие и что заинтересованные подсистемы на него подписаны.
src/main/java/.../languageserver/
cli/ context/ providers/ diagnostics/ references/ configuration/ reporters/ cfg/ mcp/
codeactions/ hover/ completion/ inlayhints/ codelenses/ rename/ folding/ semantictokens/ …
src/main/resources/ локализованные ресурсы диагностик (_ru/_en .properties), application*.properties
src/test/java/ тесты (JUnit 5); src/test/resources/ фикстуры (.bsl/.os, метаданные, ожидаемые результаты)
src/jmh/ бенчмарки JMH; docs/ (ru) · docs/en/ (en) · docs/contributing/ — для разработчиков
Используй только wrapper ./gradlew (Windows — gradlew.bat); устанавливать Gradle вручную не нужно.
./gradlew build # сборка + проверки + тесты (долго, см. ниже)
./gradlew bootJar # исполняемый fat-jar (classifier -exec)
java -jar build/libs/bsl-language-server-*-exec.jar --help # запуск; подкоманды см. выше./gradlew test --tests "*SomeDiagnosticTest" # один класс — используй это при разработке
./gradlew test # весь набор (МЕДЛЕННО)
./gradlew check # то, что гоняет CI: test + jacoco + spotless + javadoc- 600+ тестовых классов, многие перезагружают Spring-контекст (
@DirtiesContext,@CleanupContextBeforeClassAndAfterClass) → полный прогон занимает много минут (самый долгий шаг CI). Не прерывай его раньше времени, считая «зависшим»; при разработке гоняй одиночный класс через--tests. - Параллелизм — на уровне форков JVM (не потоков): на CI 1 форк, локально половина ядер (1..4),
переопределяется
-PmaxParallelForks=N. Тестовой JVM нуженmaxHeapSize = 3g. - Автоматически подключаются java-агенты jmockit и mockito.
Проект двуязычный (ru/en), в коде/ресурсах/тестах много кириллицы (1С пишется кириллицей).
- Всё в UTF-8 без BOM. Компиляция,
processResources, Sonar настроены на UTF-8. .propertiesдиагностик пиши живой кириллицей — Gradle сам экранирует их в\uXXXXчерезEscapeUnicode(заменаnative2ascii). Не экранируй вручную и не коммить уже экранированные.properties.- EOL по
.gitattributes: для большинства файлов (*.java/*.bsl/*.xml/*.md/*.json) — LF, для*.bat— CRLF. Не меняй EOL целиком; отдельные тестовые файлы помеченыbinaryили особыми правилами в.editorconfig— их whitespace не трогай. - Локаль рантайма (не только кодировка файлов!). Указанное выше про UTF-8 — это про содержимое
файлов. Отдельная проблема — локаль JVM: при
LC_CTYPE=POSIX/CJava берётsun.jnu.encodingASCII и не может декодировать кириллические имена файлов (фикстуры вродеДокумент1.xml) — падаютprocessTestResourcesи часть тестов. Нужна UTF-8-локаль. В среде Claude Code на вебе она уже задаётся репозиторным.claude/settings.json(env.LANG=C.UTF-8); вне неё запускай вручную:LANG=C.UTF-8 ./gradlew ….
Одна диагностика = несколько связанных файлов (подробные гайды в docs/contributing/ — следуй им, не выдумывай свой процесс):
- Java-класс в
diagnostics/— наследникAbstractDiagnosticс@DiagnosticMetadata. - Сообщения —
XxxDiagnostic_ru.propertiesи_en.propertiesвsrc/main/resources/.../diagnostics/. - Документация —
docs/diagnostics/Xxx.md(ru) иdocs/en/diagnostics/Xxx.md(en); встраивается в ресурсы задачейgenerateDiagnosticDocs. - Тест
XxxDiagnosticTest+ фикстуры вsrc/test/resources/diagnostics/.
Подавление в коде 1С: // BSLLS:КлючДиагностики-off / -on, либо // BSLLS-off.
Гайды: DiagnosticExample ·
DiagnosticStructure ·
DiagnostcAddSettings ·
DiagnosticQuickFix ·
DiagnosticDevWorkFlow.
- Spotless проверяет лицензионные заголовки
.java. Перед коммитом при необходимости:./gradlew spotlessApply(алиас./gradlew updateLicenses).checkупадёт без корректного заголовка. - Lombok активно используется (нужен annotation processing). Соблюдай
.editorconfig. - Не запускай «оптимизацию импортов» по всему проекту — за порядком импортов следят мейнтейнеры
(см. EnvironmentSetting). Javadoc проверяется
-Xdoclint:all,-missing. - Javadoc — про контракт, а не про вызовы. Javadoc класса/метода описывает что он делает:
параметры, результат, инварианты, побочные эффекты — но не кто и в каких сценариях его
вызывает (имена вызывающих, порядок шагов, CLI-флаги/режимы). Это чужой домен: нарушает разделение
ответственности и быстро устаревает, начиная врать. Знание «как вызывается» держи в коде
вызывающей стороны, тестах или (для обзора подсистемы) в
package-info/docs. Исключение — если без сценария контракт реально непонятен; согласовывай с пользователем. - Следуй идиомам соседних файлов. Документация — в
docs/иdocs/en/; при изменении поведения обновляй обе локали.
- Веди разработку в отдельной ветке; не пуш в
develop/masterбез явного запроса. - Не создавай Pull Request, если об этом явно не попросили. Версия проставляется плагином git-versioning по тегам/веткам — руками не правь.
- Сообщения коммитов — по Conventional Commits:
type(scope): описание(типы:feat,fix,docs,refactor,test,build,ci,chore,perf,style). Например:feat(diagnostics): add NewDiagnostic/fix(providers): ….
Плагин git-versioning (me.qoomon.git-versioning) определяет версию по git-ref'у текущего
рабочего дерева. В отдельном git worktree он не может корректно её вычислить и сборка
падает. В этом случае отключи плагин и задай версию вручную:
./gradlew build -Dversioning.disable -Pversion=0.0.0-worktree
# эквивалент через переменные окружения:
# VERSIONING_DISABLE=true ./gradlew build -Pversion=0.0.0-worktree-Dversioning.disable выключает плагин, -Pversion=… задаёт версию проекта (без неё она будет
unspecified). Флаги нужно передавать при каждом вызове gradlew в worktree.