Skip to main content

Инструментарий XBSL (1С:Элемент): линтер, LSP, документация, индекс проекта, скаффолдинг метаданных

Project description

xbsl

English · Русский

CI

The XBSL (1C:Element) toolkit: a linter with autofixes, an LSP server, a project index, platform documentation search, metadata scaffolding and an MCP server for AI agents. It works on Name.yaml (element description) and Name.xbsl (code module) pairs – before the server-side compilation that happens on deploy.

Before 0.16 the project was named xbsl-lint (the xbsllint package). The old names keep working: the xbsllint* commands are aliases of the new ones, import xbsllint returns the xbsl modules, and both spellings of the environment variables and entry-point groups are honored.

Not affiliated with 1C. "1C:Element", "1C:Fresh" and related names are trademarks of their respective owners. Language data is generated from your own distribution. See NOTICE.

Development notes and updates (in Russian): the 1C × AI: engineering workshop Telegram channel.

Why

1C:Element has no external tooling: the only code check is the server-side compilation on deploy – it is slow and knows nothing about project conventions. xbsl gives fast local feedback, catches what the compiler does not check at all, and takes over the metadata mechanics – creating objects, attributes and forms.

Step 1: generate the language data

The linter relies on language tables (bilingual keywords, operators), an stdlib type catalog, and the configuration metamodel (element properties). XBSL is built on Eclipse Xtext + ANTLR; these are extracted from your 1C:Element distribution (the InternalBsl.g grammar, the documentation, and the .xcore metamodel) and are NOT bundled in this repository. Generate them locally:

python tools/extract_grammar.py   --dist "<path to the 1C:Element distribution>"
python tools/extract_stdlib.py    --dist "<path to the 1C:Element distribution>"
python tools/extract_metamodel.py --dist "<path to the 1C:Element distribution>"

The scripts auto-detect the platform version and place the data under xbsl/data/element/<version>/ (this folder is gitignored). Without the data, the linter and the tests will tell you to generate it. Pass --data-dir (or set XBSL_DATA_DIR) to write the data somewhere else – for instance into a private package that ships it, see Extending.

Step 2: install and run

pip install xbsl            # or, from a clone: pip install -e .
xbsl path/to/sources        # or: python -m xbsl path/to/sources

The extractors from step 1 ship with the repository, not with the PyPI package – clone the repository to generate the data.

Flags: --list-rules, --where (data root, source and versions), --select/--enable/--ignore (by rule id, rule group – the part of the id before / – or tier letter), --fix, --baseline/--write-baseline, --element-version, --data-dir, --lang, --format text|json|codeclimate. --fix repairs the mechanical findings in place – trailing whitespace, typography characters (em dash → en dash, ..., curly quotes and comment guillemets → straight), and mixed newlines (normalized to the dominant style) – then reports whatever is left. It only applies unambiguous edits and only for rules active in the run (so --fix --enable typography also pays down the em-dash/guillemets debt); anything needing judgment is never touched. For editor integration, --stdin --filename NAME checks a single buffer read from stdin (per-file rules only); the JSON payload ({diagnostics, summary}) is the same one the MCP server returns. xbsl --index PATH dumps a JSON index of the project to stdout instead of linting – the objects (with tabular sections, module-declared local types and the member families for dot completion), the method declarations with their annotations and the named form components, with POSIX paths relative to the root and 1-based lines – for go-to-definition and completion in editors. --format codeclimate emits a GitLab Code Quality report (Code Climate issues) with paths relative to the current directory – run it from the repository root and save the output as the codequality artifact.

Output language

Rule titles and diagnostic messages come in Russian and English. The language is picked by --lang ru|en > the XBSL_LANG env var > the system locale > Russian. Type names, keywords and other XBSL text inside a message are never translated – only the wording around them. The MCP server and the web panel follow the same setting (the web panel also has an in-page RU/EN toggle).

Use in CI

xbsl exits non-zero only when a run produces an error-severity finding, so it works as a pipeline gate as-is – warnings and info do not fail the build. The one prerequisite is the language data (see Step 1): generate it in the job (the extractors ship with the repository, so check the repo out), or depend on a package that ships the data via the xbsl.data entry point (see Extending) and just pip install it.

GitHub Actions

lint:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-python@v5
      with: { python-version: "3.12" }
    - run: pip install xbsl
    # generate the data from your 1C:Element distribution (or install a package that ships it):
    - run: |
        python tools/extract_grammar.py  --dist "$ELEMENT_DIST"
        python tools/extract_stdlib.py   --dist "$ELEMENT_DIST"
        python tools/extract_metamodel.py --dist "$ELEMENT_DIST"
    - run: xbsl e1c/          # fails the job on any error-severity finding

GitLab CI (Code Quality widget)

--format codeclimate writes a Code Climate report that GitLab renders inline on the merge request. Run it from the repository root and save the output as the codequality report. The command still returns non-zero on error-severity findings, so artifacts.when: always keeps the report even when the job gates the pipeline (drop the gate with a trailing || true if you want the widget only):

lint:
  script:
    - pip install xbsl
    - xbsl --format codeclimate e1c/ > gl-code-quality-report.json
  artifacts:
    when: always
    reports:
      codequality: gl-code-quality-report.json

Rule tiers

  • A. Structure and YAML.xbsl/.yaml pairing, schema validity, Ид as a UUID, Ид uniqueness, Имя matching the file name.
  • B. Text and conventions – typography (en dash, straight quotes), encoding/BOM/newlines/trailing whitespace, indentation and line length.
  • C. Code structure – balance of blocks and ;, brackets, unused local and loop variables, a structure reference field that must be обз, plus the platform's code style conventions (the style/ group, see below).
  • D. Semantics – against platform data and the project itself: types, enumeration values, cross-file consistency (see below).

The type rules of tier D cover every type position in code (новый, как casts, annotations, signatures) and every Тип: value in yaml (unions А|Б|?, generics, nullable): the root must be a known type – stdlib, a project object or a module-declared local type – and a dotted chain rooted at a project object must stay within the family that object generates: the derived types extracted from the distribution docs (Ссылка, Объект, СоздатьОбъект, the automatic forms...), its tabular sections and module structures. Namespace-qualified references (Справочник.X.Ссылка) also check that the object exists under that kind, and the values of project enumerations are verified both in code and in yaml bindings.

The cross-file rules of tier D catch what the compiler reports late or not at all: a yaml handler missing from the paired module, a foreign-subsystem type used without an Импорт: entry, a dynamic list typed by the automatic list form that misses an attribute of its object, a cross-component Компоненты.X.Метод() call to a method without a visibility annotation, environment mismatches (@НаСервере called from a client handler without @ДоступноСКлиента, a client-only module used from an HTTP service), reserved names (Тип/type as a field or parameter, a component property named like a built-in one), methods that nothing references, and top-level yaml properties against the configuration metamodel. The query/ group parses Запрос{ ... } blocks and verifies the tables of ИЗ/СОЕДИНЕНИЕ against the project objects and their tabular sections; a block with constructs outside the supported subset (temporary tables, unions, subqueries) is skipped whole rather than guessed.

Queries: IN with a subquery over a composite type (rule query/in-subquery-composite)

A platform standard: IN with a subquery over an expression of a composite type is implemented inefficiently on most DBMSs, so the condition is written with EXISTS instead. The rule is a warning – the standard is mandatory:

WHERE T.Value IN (SELECT F.Value FROM Filters AS F)                    // warning
WHERE EXISTS (SELECT 1 FROM Filters AS F WHERE F.Value = T.Value)      // this way

A type counts as composite when the yaml spells two or more alternatives (Строка|Число|?): the ? is not a type but the admissibility of Неопределено, and Массив<Строка|Число> is not composite either. Only a field whose type is known for sure is questioned: Alias.Field or Table.Field, where the alias is unambiguous within the block and the field is found in the table's yaml; a list of values (IN (1, 2, &Codes)) is not what the standard is about. Both spellings of the query language are understood (В/IN, НЕ/NOT, ВЫБРАТЬ/SELECT).

Project properties (the project/ rules)

Three rules from the standard "Filling in the project properties": Поставщик and Имя are identifiers built from the presentations (every word capitalized: КабинетСотрудника, НовыеЭлементарныеТехнологии); Представление and ПредставлениеПоставщика are filled in – the official name of the project and of the company that developed it; Версия is three numbers A.B.C (semantic versioning), not 1.0.

Names of project elements (the naming/ rules)

Twelve rules from the platform standard "Names of project elements" – it is mandatory in new code, so all of them are warnings. They read the descriptions (.yaml): the name of the element itself and the names of its attributes, dimensions, resources, tabular sections and enumeration values.

The number of a name is checked against the kind: catalogs, documents, registers and tabular sections are named in the plural, enumerations and structures in the singular (naming/number). This is morphology, not a guess by the ending: Номенклатура is singular and the standard allows it, while Программы and Акции without the case read as a genitive singular. Needs the [morph] extra (pip install "xbsl[morph]"); without it the rule stays silent.

The rest: the letter ё and underscores in names, an abbreviation written as one word (Ндс, not НДС), an English term as the original (Xml, not Хмл), Вид rather than Тип for enumerations, the kind inside its own name (ОтчетЗависшиеЗадачи), filler words (Управление, Менеджер), an environment suffix on a common module (ОбменДаннымиКлиентИСервер – the environment is a property, not a name), a boolean attribute named by a negation (НетОшибок instead of Успешно), an empty Представление, and the prefixes required for certain kinds (КлючДоступа, ПравоНа, Навигация).

Code style conventions (the style/ rules)

Twenty-one rules that follow the platform documentation ("Code style conventions" and "Language idioms"): layout and expression wrapping, naming, type descriptions and signatures, collection literals, string interpolation, and checks of boolean values and Неопределено.

Rules that clean code already satisfies are enabled by default (warning) – they guard against regressions. Rules that typically fire on accumulated legacy debt are info and disabled; enable them to measure the debt and pay it down:

xbsl path/to/sources --select style     # ONLY these rules (replaces the default set)
xbsl path/to/sources --enable style     # the default set PLUS these
xbsl path/to/sources --ignore style     # the default set minus these

--select, --enable and --ignore accept a rule id, a group (the part before /) or a tier letter, repeated or comma-separated. --select narrows to exactly the given rules; --enable switches on off-by-default rules on top of the defaults.

Запрос{ ... } blocks (the query DSL) and string literals (HTML/CSS/SVG in web views) are excluded from these checks. Not covered, and left to the author and review: indentation being a multiple of four, collection idioms, Строки.Соединить() for bulk concatenation, the ?. / ?? idioms, and выбор instead of an иначе если chain.

Baseline: adopt a rule on a legacy codebase

To enable a rule over code that already violates it without drowning in legacy findings, freeze the current findings into a baseline and hold only new code to the rule:

xbsl e1c/app --enable style --write-baseline baseline.json   # freeze the debt once
xbsl e1c/app --enable style --baseline baseline.json         # only NEW findings surface

A finding's identity is (file, rule, message) with an allowed count, so moving a line keeps its finding suppressed while a genuinely new violation surfaces. The summary reports how many findings the baseline suppressed and how many of its entries are now stale (debt paid down) – a signal to rewrite the file. Paths are stored relative to the baseline file, so commit it at the repository root and run the linter from anywhere.

The same file also records point exclusions with their reasons: an entry's value is either a bare count or {"count": N, "reason": "..."} – the reason says why the code is right on purpose. Reasons are written by the "Exclude the finding" lightbulb action of the VS Code extension (or by hand); --write-baseline keeps the reasons of the identities that survive a rewrite. The LSP server accepts the same --baseline FILE flag, so exclusions disappear in editors too. The identity includes the message text: write and check the baseline under the same output language.

Metadata scaffolding

The toolkit takes over the metadata mechanics: UUIDs, indentation, precise yaml insertions, duplicate checks and section/kind compatibility. The same operations are exposed through the CLI (subcommands, JSON output), MCP (the meta_* tools for agents) and LSP (the xbsl/meta* custom requests that power the VS Code metadata tree).

xbsl new-project . vendor App                        # Проект.yaml + Проект.xbsl + a subsystem
xbsl new-object vendor/App/Основное Справочник Товары
xbsl add-field vendor/App/Основное/Товары.yaml реквизит Цвет --type Строка
xbsl add-form . --name Товары                        # object + list forms, registered
xbsl new-object ... HttpСервис Каталог --routes "GET /, POST /, GET /{id}"
xbsl add-route  .../Каталог.yaml "DELETE /{id}"      # url template + handler stub
xbsl add-subsystem vendor/App Задачи
xbsl object-info . --name Товары                     # fields, tabulars, forms, namespace
xbsl project-info .                                  # projects, subsystems, objects by kind

Forms are generated with real content: input fields per attribute (including the standard Наименование / Номер / Дата and hierarchy support), dynamic-list columns, tabular-section tables, a report form with parameters; the form is registered in the owner's Интерфейс section. --dry-run prints the changes (with full file texts) without writing – this is how the VS Code extension applies them through its own undo-friendly edits.

Extending: your own rules, data and severities

Three entry point groups let a separate package extend the linter without forking it. This exists for teams whose rules or language data cannot be published: keep those in a private package that depends on xbsl.

# pyproject.toml of your package
dependencies = ["xbsl>=0.16"]

[project.entry-points."xbsl.rules"]
myproject = "myproject.rules"        # importing the module runs its @rule decorators

[project.entry-points."xbsl.data"]
myproject = "myproject:data_root"    # a path, or a callable returning one

[project.entry-points."xbsl.severity"]
myproject = "myproject:severity_overrides"   # {rule id: "error"|"warning"|"info"|"off"}

Packages that declared the groups under the pre-rename name (xbsllint.rules/xbsllint.data/ xbsllint.severity) keep working: the legacy groups are scanned after the new ones.

The severity dict (or a zero-argument callable returning one) raises or lowers the default level of any rule – built-in or plugin – for every run in this installation: a project may treat, say, style/abbreviation-case as a warning while the published default stays info. "off" removes a rule from the default set (an explicit --select/--enable still turns it on, at its base level).

Install the package and the CLI, the MCP server and the web UI all pick everything up – no flags, no config file. A failing entry point raises instead of warning: a linter that silently drops a rule stays green in CI and guarantees nothing; an override naming an unknown rule id or level raises for the same reason. XBSL_NO_PLUGINS=1 ignores every external package (built-in rules, bundled data and default severities only).

LSP server (experimental)

xbsl-lsp (the [lsp] extra: pip install "xbsl[lsp]") runs the linter as a long-living Language Server over stdio: live per-file diagnostics as you type, project-wide diagnostics on save, go to definition, completion and hover over a resident project index, and quick-fix code actions - without paying the interpreter start-up cost per call. Flags: --project-root (the sources root relative to the workspace folder), --select/--ignore/ --enable, --data-dir. Any LSP-capable editor (VS Code, Neovim, JetBrains) can spawn it.

Documentation (searching the Element reference)

tools/extract_docs.py extracts the Element reference from a distribution (the server-with-IDE .car) into a docs.sqlite next to the language data: the stdlib pages (a type, its methods, properties, parameters) with cleaned HTML, a full-text index (SQLite FTS5, from the standard library) and canonical links back to the primary source (https://1cmycloud.com/docs/help/..., taken from the distribution's sitemap.xml). Page images are stored alongside. The 1C reference is copyrighted, so the database is not shipped in the package – you generate it from your own distribution, like the language data (step 1).

python tools/extract_docs.py --dist "$ELEMENT_DIST"

The runtime API xbsl.docs (search, page, tree, for_symbol, asset) reads docs.sqlite; with no database the search is simply empty. It powers the MCP tools (below) and – later – the reference panel in the VS Code extension.

MCP server

A thin adapter over the same core: an agent (e.g. Claude Code) can call the checks as tools and receive structured diagnostics.

pip install -e ".[mcp]"
claude mcp add xbsl -- xbsl-mcp

Tools: lint_paths(paths), lint_source(filename, content), list_rules(); documentation search – docs_search(query), docs_page(id), docs_symbol(name) (needs the docs.sqlite database, see above); metadata scaffolding – meta_new_project, meta_new_object, meta_add_field, meta_add_route, meta_add_form, meta_add_subsystem, meta_object_info, meta_project_info. Every writing meta_* tool applies the changes and returns the lint of the written files in the same response – creation and validation in one round trip. The core and the CLI do not require mcp – it lives only in the [mcp] extra.

Web interface

A local page: point it at a project folder and see the diagnostics. Standard library only (no external dependencies), binds to 127.0.0.1 only.

xbsl-web            # then open http://127.0.0.1:8771/

Per-tier rule toggles, a data-version selector, severity/text filters, dark/light theme; clicking a diagnostic opens the file in VS Code (vscode://).

Editor support (VS Code)

A VS Code extension in editors/vscode gives .xbsl syntax highlighting, live diagnostics as you type (--stdin), workspace diagnostics on save (a full linter run in the background brings the project-scope rules into the editor), index-based go-to-definition and completion across the project (xbsl --index), a form preview with a properties panel, and a deploy button powered by elemctl. It is published on the Marketplace and Open VSX; its README covers settings, behavior and requirements. See also the companion XBSL Debug extension from the elemctl project.

Element versions

The data is versioned by platform version:

xbsl/data/element/
    index.json            # { available: [...], default: "<version>" }
    <version>/{language.json, stdlib.json, metamodel.json}

Pick a version with --element-version / the XBSL_ELEMENT_VERSION env var / the index default; --version shows what is available. Add a new version by re-running the extractors with a new --dist.

The data root itself is resolved in this order: --data-dir > XBSL_DATA_DIR > a root supplied by an installed xbsl.data entry point > xbsl/data/element inside the package.

Tests

pip install -e ".[dev]"
pytest

Data-dependent tests are skipped automatically when the data has not been generated.

License

MIT – see LICENSE. Trademarks and data provenance – NOTICE. How to add a rule – CONTRIBUTING.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xbsl-0.16.0.tar.gz (250.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xbsl-0.16.0-py3-none-any.whl (207.1 kB view details)

Uploaded Python 3

File details

Details for the file xbsl-0.16.0.tar.gz.

File metadata

  • Download URL: xbsl-0.16.0.tar.gz
  • Upload date:
  • Size: 250.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for xbsl-0.16.0.tar.gz
Algorithm Hash digest
SHA256 2e675c01852f016db181468cdc586a397e96826947f477fbab42270803d3d08a
MD5 f53f93b165afd2f8f6dadf5306af84f4
BLAKE2b-256 3c68ea8e644090ea50b4ba86f491c46e9b2ec2c65df5d212ec069def724901f6

See more details on using hashes here.

File details

Details for the file xbsl-0.16.0-py3-none-any.whl.

File metadata

  • Download URL: xbsl-0.16.0-py3-none-any.whl
  • Upload date:
  • Size: 207.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for xbsl-0.16.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eab213b6630ec67f3560a81ec354a6d32090623cc2e9a61322c4c61e33a3e221
MD5 44b643cafeb82e2d261107146463bab6
BLAKE2b-256 a4d5217e9da01d5beb16923b0273d75693a8a5541dc03f4f36045a7b323a7b06

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page