Skip to content
XBSL (1C:Element)
English
Esc
↑↓navigate↵open⌘Jpreview
On this page

XBSL linter rules

The full list of linter checks, with severities and scope.

The full list of linter checks. This file is extended as rules are added, and the live list comes from xbsl --list-rules or the MCP list_rules. Currently there are 280 rules.

The table describes the toolkit as it ships. An installed plugin may add rules of its own and override severities and default states (see Extending), so the live list can differ from this one. xbsl --list-rules shows what your environment actually runs, and XBSL_NO_PLUGINS=1 shows the set below.

Boundary: the linter complements the compiler, it does not replace it

The linter works over text, the AST and the project model. Its rules know types at the first hop: the declared nominal type of a variable and its members, the project objects and the types they generate, enumeration values, the global types of the linked libraries (from the .xlib archive).

The engine does infer the type of an expression. xbsl.typeinfer answers for a receiver, a member, a constructor, a cast and a non-null operator, and the inference of chains and locals feeds hover and completion in the editor. Over a whole project it answers with a set of types that keeps a union, the empty value and the Null of a query column, and it knows the project’s own names: the rows of Query{...} are typed by the select list, the attributes by the yaml, the structures and methods by the modules. Five rules judge an inferred type and repeat warnings of the platform IDE: code/redundant-cast, code/cast-to-non-null, code/redundant-undefined-guard and code/redundant-type-check, plus code/deprecated-api for overload selection. They say nothing about an expression whose type the inference cannot name. The other rules judge by the declared types.

Some of the findings the compiler would catch as well: an unknown type, an argument count, a non-exception in catch, a return not matching the signature. The linter’s value there is timing. It shows them earlier, in seconds on your own machine, before the build and the deploy, and it points at the exact spot. The rest the compiler never checks at all: code-writing conventions, typography, project structure (duplicate Id, file pairing), secrets in the sources. Unused variables and imports get only a warning in the platform IDE, and a build goes through with them.

What the linter does not do is anything that needs full inference of expression types: a leaked resource in the general case, whether the type of a returned value matches the signature. Those two are worth separating. A structural return mismatch - a value in a void method, a bare return in a typed one - is caught by code/return-mismatch. A return of a string from a method declared : Number slips through, because telling that apart needs the expression’s type. A resource is judged only in the one shape where the declaration itself says everything: code/unclosed-resource follows a closeable from its declaration to the loop over it in the same method. A resource that travels through calls or collections stays out of reach.

Code correctness is verified by the server-side compilation on deploy. The linter runs before it and removes common mistakes early.

How to read the table

  • Rule – the group/name identifier. The group (the part before /) lets you enable and disable rules in bulk.
  • Level – error (a build and CI should fail), warning (a convention is broken), info (a hint, usually off).
  • Default – ✓ the rule is in the default set, – it is enabled explicitly.
  • Scope – file (the rule sees one file) or project (needs the whole-project index: duplicate Ids, unknown types, cross-module calls).
  • What it checks – a sentence or two about the finding. A “details” link leads below the tier table, where the exceptions, the examples and the answer of the platform live.
  • The link at the end of a description – the platform documentation section behind the rule. In VS Code the code of such a rule in the Problems panel opens that section right in the editor.

Tiers

Rules are split into tiers A-D by what they rely on. A tier is also a quick filter for --select/--ignore (alongside the group and the identifier): --select A,B runs only structure and text, --ignore D drops the semantics over stdlib.

Reading the columns: error · warning · info; ✓ – in the default set, – turned on explicitly; the scope is one file or the whole project.

Tier A - structure and YAML

The file exists, parses, the object has a unique UUID, the name matches the file.

Rule Scope What it checks
yaml/valid ✓ file YAML does not parse
yaml/duplicate-key ✓ file A scalar key set twice in one YAML mapping: the loader silently keeps the last value, and the compiler rejects the file on deploy details
yaml/duplicate-import ✓ project A namespace repeated in the Import section of an element: the second entry adds nothing details docs
yaml/id-uuid ✓ file Id is not a UUID
yaml/id-required ✓ file The object has no Id
yaml/name-matches-file ✓ file Name does not match the file name
yaml/id-unique ✓ project Duplicate Id in the project
yaml/standard-field-length ✓ file A standard field longer than the platform limit (Name over 400 characters, Code over 50) - apply rejects the field and it drops out of the object docs
yaml/document-date-required ✓ file A document without the standard Date attribute among its Attributes: the attribute is required, and the build refuses the document docs
yaml/ref-needs-nullable ✓ file A reference type in a type position without ?: a reference has no default value, so the compilation fails details docs
yaml/union-needs-nullable ✓ file A union type without the empty member in a type position (`String
yaml/contract-facet-mismatch ✓ project The restrictions of an attribute that overrides an entity contract property disagree with those of the property (the string length, the lengths and bounds of a number) - the compilation fails details
yaml/contract-standard-length ✓ project The length of a standard attribute (Name, Code, Number) disagrees with the MaxLength of the entity contract property it overrides - the compilation fails details
yaml/register-entity-contract ✓ project A register names the object type of an entity contract among the contracts of its types (Contracts: - <Contract>.Object): a register implements type contracts only, and the compilation fails details docs
yaml/report-parameters-alias ✓ file The query parameters of a report under the Parameters key: the metamodel lists it as another spelling of QueryParameters, while the server rejects it as an unknown property. The fix renames the key details docs
yaml/no-expression-in-literal ✓ file An =... expression inside a literal-typed node (Font: {Type: AbsoluteFont, Size: =...}) - the platform accepts only a literal there, compute the whole object instead docs
yaml/localization-key-unique ✓ file A key declared twice in a LocalizedStrings dictionary: the apply rejects the whole project details docs
yaml/unused-component ✓ project An interface component placed nowhere and created nowhere: neither as a Type value in markup nor by new in code. Dead markup ships with the build and the translation details
yaml/duplicate-subtree – project A markup subtree repeats the shape of a subtree in another file: a new form was started by copying the neighbouring one, and a change now goes into both details
project/identifier ✓ file Project name or vendor is not an identifier docs
project/presentation ✓ file Project presentation is empty docs
project/version ✓ file Project version is not A.B.C docs
structure/xbsl-pair ✓ file Module .xbsl without a paired .yaml
project/path-matches-descriptor ✓ file The {{vendor}}/{{name}} path diverged from the descriptor – a build refuses the project before compiling docs
yaml/unknown-component-property ✓ file A markup key the component does not declare while another component of the ui schema does: the apply rejects the node as an unknown property details docs
yaml/inline-command-name ✓ file A Name on a command declared inline in the markup: the apply refuses the node and rolls the project back details docs
yaml/list-scroll-without-loading ✓ file A list with Navigation: None never loads the tail: a vertical scroll moves through one portion, and a list over an array without a scroll of its own keeps the automatic portion of ten rows details docs
yaml/dynlist-scroll-without-loading ✓ project The same for a dynamic list whose hierarchy is left to the main table (UsedHierarchy not written): over a catalog without a hierarchy, a document or a register the list is flat and Navigation: None drops the tail details docs
yaml/hierarchy-bare-value ✓ file A bare Disabled, Default or Auto in UsedHierarchy of a dynamic list: the apply refuses the value as one whose type is not specified. The fix writes the typed node, or takes Auto out details
yaml/compute-permissions-by ✓ file ComputePermissionsBy against the access settings of an entity: no list while a privilege computes its permissions for each object, or a list while none does - the build refuses both details
yaml/compute-permissions-by-unknown ✓ file A name in ComputePermissionsBy that is no field of the element - a misspelt or undeclared attribute, a standard attribute left out of Attributes, a tabular section: the build answers that the attribute is not found. A computed field (DeletionMark, Presentation) fails the apply of the build details
yaml/soap-handler-name ✓ file A SOAP service handler whose Name holds a letter outside Latin, a whitespace or a punctuation character the build refuses, or starts with a digit, a hyphen or a dot: the name becomes an operation of the WSDL description, and the build refuses it docs
yaml/root-url-cyrillic ✓ file A RootUrl of an HTTP or a SOAP service with Cyrillic letters: the build takes it, and no request reaches the service. The quick fix writes the address in Latin letters details
yaml/component-member-unique ✓ file A name repeated among the own Properties and Events of an interface component: the two lists are one namespace, and the build refuses the name as not unique details
yaml/plain-comment – file A # comment in an element description: the visual editor writes the file out again from the model and keeps only a ## documentation comment at the head of a documentable node (the element, a component, a declared property, a tabular section and the like). The fix respells a block that already stands in such a place and steps a block standing before the - of an item inside it; anything else is reported with the nearest node that holds a comment
yaml/doc-comment-misplaced – file A ## block that stands where the environment does not read it - before the - of an item, above a single property, on a node without a documentation comment (a standard attribute such as Code or Name, a command, a dynamic list field). It is lost the same way a # comment is. A separate case is an instance of a project or a library component in a list: with a ## block on such a node the server does not apply the project, and the rule names this reason

Tier A rules in detail

yaml/duplicate-key. The schema checks read the already merged document, so the lost value surfaces nowhere else. The second occurrence is flagged and every one after it, with the line of the first. The << merge key and non-scalar keys are left alone, and keys are told apart the way the loader tells them apart: by tag and by text.

yaml/duplicate-import. The short and the full name of the own project are one namespace, so a pair of them counts as a repeat too. The platform IDE does not check the Import section. The fix removes the extra entry.

yaml/ref-needs-nullable. Both a field of its own and a type argument of a component are written this way: Goods.Reference, Edit<Goods.Reference>. The compilation answers Default value initialization is not supported.

yaml/union-needs-nullable. The platform builds a default value for a single type only; for a set of types without Undefined it gives up at once, whatever the members are. A probe got Default value initialization is not supported for types ... on an attribute of a catalog and of its tabular section, on a dimension and a resource of a register, on a field of a structure and of a storable structure, on a constant, on a property of an interface component and on a property of an entity contract. What compiles: the empty member (String|Number|?), a DefaultValue next to the type, a structure field with Required: True, a parameter of an event and of a virtual table, a property of a type contract. A property of an entity contract has no DefaultValue key, so there the empty member is the only way out. Three positions fail with messages of their own, and the finding quotes each: a write or delete parameter (“The type composition of parameter … must contain “Undefined” type“, no default key there either), a report query parameter (no default value is set for the parameter) and an input field around a union, Edit<String|Number> (“Parameter … must have a default value”, a Value bound to the field does not help). A write or delete parameter demands the empty member of a single type as well: a second probe got the same refusal for Boolean and Number alone. A union with a reference member is left to yaml/ref-needs-nullable, and so is a single reference in a write parameter, while yaml/enum-needs-nullable leaves write and delete parameters to this rule - one position gets one finding. The fix appends |?, inside the angle brackets for an input field, and ? after the single type of a write or delete parameter (Boolean?).

yaml/contract-facet-mismatch. An attribute overrides the property of the implemented contract that has its name, a table attribute the attribute of the contract table, and the compiler holds their restrictions against each other. A property without a restriction does not allow one on the attribute (“Restrictions must not be set for the attribute that overrides entity contract property”), and a restriction is any key of the group: Multiline or LengthControl alone make the attribute a restricted string. A restricted property demands the same restriction (“No restrictions are set …”), and the values must be equal (“… must be equal to 50”). A property with ReadOnly: True is softer: it lets an unrestricted property’s attribute restrict itself and lets a restricted one be stricter, never wider (“… cannot be greater than 50”). A number restricted by one key takes the defaults for the rest - integer part 10, fractional part 0 - and a bound the property sets and the attribute does not is an error of its own. Types must match, and an array or a union of a string with a number is left alone. A contract that names base contracts has their properties too, and the tables of the same name gather their attributes: a probe held the attribute against the property of the base, and of the base of the base, and the message named the contract that declares the property; a property the derived contract declares again wins over the base. A register cannot implement an entity contract at all (“a type contract is expected”, reported by yaml/register-entity-contract), and a type contract has no restrictions to compare. The fix sets an unequal or missing string length to the property’s value.

yaml/contract-standard-length. A standard attribute always has a length: Name 150, Code 7, Number of a document 9, unless Length says otherwise. A contract property of that name without MaxLength fails the implementation with “The maximum length for property “Name” is not set in entity contract“, a different MaxLength with “… must be equal to 100”, and a read-only property only caps the length (“… cannot exceed 100”). A numeric code is measured by IntegerPartLength, and a probe confirmed it: “The integer part for property “Code” is not set“ without one, the same “must be equal” and “cannot exceed” otherwise, the default 7 met in silence. A property of a base contract counts the same way. The fix sets Length on the attribute; a missing length is added in the contract by hand, or the property is made read-only with the largest length the implementations need.

yaml/register-entity-contract. A register takes part in contracts through the types it generates, under TypeOptions: InformationRegister.Record: Contracts. The documentation lists both registers among the implementations of a type contract and neither among those of an entity contract, which only the object type of a catalog, a document, an exchange plan, an integrable application or a settings storage implements. A probe on an information register that named <Contract>.Object of an entity contract got “Invalid type of contract …; a type contract is expected”. The contract is found by its short name in the project; a name two contracts share, a contract from a library and a bare name without the Object facet are left alone. There is no fix: implement a type contract instead, or keep the data in an element that can implement the entity contract.

yaml/report-parameters-alias. The metamodel read from the distribution lists Parameters as a second spelling of the QueryParameters property of a report, so a check that trusts it takes the key for valid. The server does not: a probe got the unknown property refusal for it. The English Parameters is not declared for a report at all and fails the same way. The fix renames the key in the spelling of the file; when the report already has QueryParameters, the two lists are merged by hand.

yaml/localization-key-unique. Strings and Templates share one namespace, and a translation file is judged alongside the dictionary. The apply answers “Name is not unique” and rolls the project back.

yaml/unused-component. code/unused-method cannot see such a component: its methods are called by its own yaml. A use is a yaml value or any word of a module, and a name standing as a key of a localization dictionary does not count. A yaml file that does not parse counts with all its words, and the translation dictionary does not count at all. An entry point and VisibilityScope: Global are never judged: that is the public surface of a library. Without a project descriptor among the linted files the rule stays silent, or a component placed outside the linted subset would look dead.

yaml/duplicate-subtree. Names, ids and texts are left out of the shape of a subtree. The 40-node threshold is measured: below it the rule catches layout, not copies. A repeat inside one file, the data source of a list and a localized-strings dictionary with its translations are never judged, and only maximal groups are named. Off by default: how much sameness is too much is a decision of the project.

yaml/unknown-component-property. An example: PlaceholderText on a Checkbox, which is a property of Edit. A name no component declares is left alone: the documentation does not list the yaml keys in full.

yaml/inline-command-name. Both an inline command-interface fragment and a single-command property look like this. The apply answers: “a command name is allowed only in command-interface-fragment project elements”. Reach the command through the handler parameter, and give it a name only by moving the fragment into a project element of its own.

yaml/list-scroll-without-loading. PageSize sets the portion and the scrolling moves through that portion alone: the list search still finds a row the scrolling never shows. Navigation: LoadingOnScroll cures it. A list over an array without a scroll of its own is judged too while PageSize is automatic (ten rows): the page scrolls around one portion, and the cure is a page size by the limit of the data or loading with a scroll of the list’s own. A tree source and a hierarchical dynamic list load on scroll whatever is written and are not judged, nor is an expression in Navigation. A dynamic list is judged here when its source declares it flat - UsedHierarchy as the typed node {Type: HierarchyMode, Value: Disabled}, the spelling of the platform’s own examples; one whose hierarchy is left to the main table is judged by yaml/dynlist-scroll-without-loading, and one built in code is not judged. A plain scalar in UsedHierarchy is not judged at all: on a live server a bare Disabled, Auto or Default failed the apply (“the value type is not specified” - the word fits the enumeration and the string at once), while a qualified word applied even with a value no enumeration has (HierarchyMode.NoSuchValue), so HierarchyMode.Disabled is read as the name of a hierarchy, not as the flat mode.

yaml/dynlist-scroll-without-loading. The project half of the rule above: UsedHierarchy not written leaves the hierarchy to the main table (“Auto interprets the query of the dynamic list depending on whether it supports hierarchy”), and the table is read from the project. Judged is a list over a catalog that declares none of Hierarchical, Hierarchy, AdditionalHierarchies and DefaultHierarchy, or over a document, a register, an exchange plan, a settings storage or an integrable application - the platform gives hierarchies to catalogs alone. A table outside the project, a data journal, a virtual table, a table derived from a catalog (its groups) and a name shared by elements that do not all agree are left alone. The findings and the fix are those of the file rule; the rule is split off so that the editor keeps checking the file on every keystroke and reads the project on save.

yaml/hierarchy-bare-value. UsedHierarchy of a dynamic list takes Auto, a HierarchyMode or a string, the name of a hierarchy of the main table. A mode written as a bare word - Disabled, Default, Auto - is none of the three to the server: a probe on a live server showed that the apply stops with “the type of the value is not specified” at the line of the property, over a catalog with a hierarchy and over one without. A quoted word or any other word is read as the name of a hierarchy and applies, and so does the typed node {Type: HierarchyMode, Value: Disabled} of the platform’s own examples; a word qualified with the enumeration (HierarchyMode.Disabled) is read as a name too, so it is no cure. The fix writes the typed node in the language of the file, and takes the line out for Auto, which is what an unwritten property means; a property inside a flow mapping keeps the finding without a fix.

yaml/compute-permissions-by. An entity whose access settings compute a permission for each object - a privilege set to PermissionsComputedForEachObject, or the default set so while some privilege is left out - reads the permissions of an object from the attributes ComputePermissionsBy lists, and the build checks the list both ways. With no list, or an empty one, it refuses the description with “Attributes for calculating object access permissions are missing” at the start of the AccessControl block; the standard permissions of a settings storage are the exception, the build takes attributes of its own then. With a list and no permission computed for each object it answers “It is not allowed to specify attributes for calculating access permissions without configuring access permissions calculation for each object” at the first attribute. A probe on a server gave both answers for a catalog, a document, a settings storage and both kinds of an information register. The rule judges the kinds whose access settings have the property at all: a catalog, a document, an exchange plan, a settings storage, an integrable application and the registers.

yaml/compute-permissions-by-unknown. The build answers Attribute "X" is not found at the name in the list. A probe on a server gave that answer for a misspelt attribute, for the Name of a catalog and the Number of a document left out of Attributes, for Id and for a tabular section, and took a declared attribute, the dimensions, resources and attributes of a register, the reference, the Parent of a hierarchical catalog and the Period of a periodic register. The fields are what the element declares, the service fields it has without a declaration (DeletionMarkInstant among them) and the built-in fields of its kind: Code, SentNumber, ReceivedNumber and ThisNode of an exchange plan, the system attributes of a settings storage (Variant, Value, SettingKey, ObjectKey, Name, Shared, User) and DirectConnectionSettings of an integrable application. The name and the files of an exchange plan and of an integrable application, and the code of the latter, are declared like those of a catalog. The service set errs on the wide side, with three exceptions: an undeclared Number of a document is reported, and so is DeletionMark of a settings storage, which has none, while DeletionMark and Presentation of the other kinds are computed fields - the compiler takes them, the apply of the build then fails inside the server, and the rule says so in a message of its own.

yaml/root-url-cyrillic. Probes on a server published an HTTP service and a SOAP service with a Cyrillic RootUrl next to Latin ones. The build took them all and the application ran; the Latin addresses answered, while a request to the percent-encoded Cyrillic one got Handler of HTTP request ... not found, and the raw one did not get past the front server. The service name and the namespace of a SOAP service worked in Cyrillic and are not judged. The quick fix writes the address in Latin letters the way new-object does for a Cyrillic service name: lower-case transliterated words joined by hyphens, such as /zadachi-proekta.

yaml/component-member-unique. An interface component declares its own properties and its own events by name, and the compiler keeps the two lists in one namespace: a probe on a live server with a property and an event of the same name was refused twice, “Property name X is not unique” at the property and “Event name X is not unique” at the event. The rule reads the top-level Properties and Events of the component and reports every repeated name after the first, naming the line of the first; the markup under Inherits is another namespace and is not read. There is no fix - which of the two to rename is the author’s call. add-field refuses such a name as well.

Tier B - text and conventions

Encoding, newlines, whitespace, typography (dashes, quotes, ellipsis, characters off the keyboard), the wording of comments, the English of the translation dictionary, line length, secrets in the sources.

Typography reads the resource files of the project as well - the .css, .js, .svg and .html that lie under Resources. A subsystem ships them to the browser as they are, so the prose in them reaches the reader the same way the prose of a module does. Judged there are the comments of all four formats and the text a user reads on the screen: <title>, <desc> and <text> of an SVG, the text nodes of an HTML page. Code is left alone - selectors, identifiers, tag and attribute names, attribute values, the string literals of a script or a stylesheet. The comment/ group reads the comments of those files as well. The other rules of the tier keep to the module and the element description; translation/english-shape, comment/first-person and comment/emphasis-caps also read the files of the translation dictionary.

Rule Scope What it checks
security/hardcoded-secret ✓ file A key or a password as a literal
typography/em-dash – file Em dash in a comment - of a module or of a resource file - and in the text of a page; the en dash is the one to write
typography/ellipsis ✓ file The ellipsis character where three dots belong: a comment, and the text of an SVG or of an HTML page
typography/curly-quotes ✓ file Curly quotes wherever they turn up: a comment, a string literal of a module, the text of a page
typography/guillemets-comment – file Guillemets in a comment, in a resource file too; in the text on the screen they are the right quotes and are left alone
typography/yo-in-text – file The letter “ё” in the text a user reads: a label, an entry of the dictionary of localized strings, the text of an SVG or of an HTML page
typography/non-keyboard ✓ file A character that is not on the keyboard in a comment: an arrow, a comparison or a multiplication sign; the fix writes ->, >=, <>, x and the like, a currency sign is data and is left alone
typography/en-dash-comment – file The en dash in a comment, for a project that writes a hyphen in its code comments; the fix writes the hyphen
comment/doc-marker – file A // block right above a declaration (a method, a structure, a field, an enumeration item, a module constant): the development environment reads a documentation comment by its /// marker alone and puts only that text into the hover, the signature help and the completion. The fix respells the block; a /* ... */ block in that place is reported without one. A slash frame //// in the attached block is also reported: only three slashes are removed by the documentation reader; no automatic choice between a header and documentation is made docs
comment/subjunctive – file The subjunctive particle (would) in a comment; the finding asks for a word of condition, because dropping the particle turns a hypothesis into a statement. Concessive turns are left alone
comment/first-person – file The author speaking as “we” in a comment: a pronoun or a first-person plural verb, and “we”, “our” or “I” in the English line of a comment kept by the translation dictionary; a comment is impersonal
comment/emphasis-caps – file A word in capitals for emphasis in a comment: “not”, “only”, a negation glued on. Emphasis is a matter of wording, not of case details
comment/dash-condition – file A condition in a comment written with a dash (“the store is not set - the main one is taken”) instead of a word of condition details
comment/doc-tag-unknown ✓ file A /// line that starts with @ and is none of the four tags (@param, @Parameter, an annotation copied into the text): the environment drops it from the hover together with its continuation. The fix respells a keyword in another case and the short forms @param, @return, @throw, @exception details docs
comment/doc-tag-layout ✓ file The place of the tags in a /// block: a tag on the first line (the environment takes it for the description), a paragraph after the last tag (glued to it), no blank line between the description and the tags, the kinds out of the order of the hover, a tag without text, a dash other than a hyphen after a name. The fix inserts the blank line and puts the hyphen details docs
translation/english-shape ✓ file A trace of a mechanical replacement in an English value of the translation dictionary: an ending glued onto a word that takes none (onlies) details
whitespace/trailing ✓ file Trailing whitespace
whitespace/mixed-newline ✓ file Mixed newlines
encoding/utf8 ✓ file File is not UTF-8
style/tab-indent ✓ file Tab in the indentation docs
style/line-length ✓ file Line longer than 120 characters docs

Tier B rules in detail

comment/emphasis-caps. The rule judges a function word, any other word the same file also writes in small letters, a one-letter word inside a sentence, a negation glued on, and the capitals of the English line of a comment in the translation dictionary. Abbreviations, date masks and a cited query are left alone. A cited query is told by the keyword table of the query language in the platform data (the query section of terms.json): a keyword prose does not shout (SELECT, DESC), a keyword of several words (ORDER BY) or the head of a CASE expression or of a statement changing a temporary table (CASE WHEN, INSERT INTO Table () marks the whole line, and any other keyword counts as syntax only when code follows it. The reserved words the table does not hold (the literals TRUE, FALSE, UNDEFINED and the word TEMP) come from the list of reserved words in the same file (query_reserved, the table of the platform documentation) and count the same way, and a literal after a comparison sign is syntax too. Without the table or the list the rule falls back on short lists of its own. The fix restores the case.

comment/dash-condition. The finding suggests the wording with a word of condition. The legend of a value is left alone: nothing is named there before the state, or no verb follows the dash.

The comment/doc-tag-* rules. The environment reads a /// block with regular expressions: the description runs to the first line that starts with @, then the @parameter, @returns, @throws and @see tags (and their Russian spellings) are cut out of the rest, each running to the next such line, and a name after @parameter or @throws ends at an underscore, a dot or a lowercase “yo”. The rules report the places where that reading differs from the block as written. They judge only a block that has tags, so they are on by default, unlike the rest of the group. A structure, an exception and a constructor are not judged by comment/doc-tag-param and comment/doc-tag-result. comment/doc-tag-target leaves alone an @see written as a phrase, a single word in lowercase and a word in the other script of the project; comment/unknown-name does not judge the names these tags point at.

translation/english-shape. The rule also catches a passive followed straight by a noun phrase (“is shadowed the parameter”) and capitals the Russian key does not have. Only the xbsl-translation files are judged.

Tier C - code structure, basic syntax and code-writing conventions

Block and bracket balance, loop and method headers, local variables and the style/ group - conventions from the documentation section “Code-writing recommendations”. Every style/ rule is on by default, at warning.

Rule Scope What it checks
code/parse-error ✓ file Syntax error (a full parse against the platform grammar) docs
code/statement-no-effect ✓ file Expression statement other than a method call or throw: a build error even when the discarded expression contains a call
code/return-mismatch ✓ file Return does not match the method signature (a value in a void method, a bare return in a typed one) - the compiler rejects such code docs
code/self-assignment ✓ file A value assigned back to where it is read from: X = X, this.Field = this.Field, X -= X. The compiler rejects it and the build rolls back details
code/assign-target ✓ file The left side of an assignment cannot receive a value - a method call, a cast, this itself, or a chain through the safe access ?. - the compiler rejects the assignment docs
code/assign-readonly ✓ file An assignment to a read-only name: a val or use local, a loop or catch variable, a module constant. The compiler rejects it details docs
code/unreachable-statement ✓ file Code the execution never reaches: after return, throw, break or continue. The compiler rejects it details
code/misplaced-jump ✓ file break or continue outside a loop, and return, break or continue inside a finally section - the compiler rejects the jump docs
code/call-arity ✓ file A local call does not match its resolved signature: argument count, unknown or repeated named arguments, positional arguments after named ones, or a missing required parameter docs
code/brackets ✓ file Unbalanced brackets () [] {}
code/blocks ✓ file Unbalanced blocks and ‘;’ docs
code/ternary-and-or ✓ file A ternary right after is Type on the right of and or or: the ternary belongs to the type check, so the line compiles differently from how it reads details docs
code/query-in-loop ✓ file A query inside a loop
code/param-type-required ✓ file Parameter without a type and without a default value docs
code/duplicate-annotation ✓ file A duplicate annotation on a declaration, an exact argument-free repeat of the name: the compiler rejects such a module details docs
code/duplicate-import ✓ project A module imports a namespace a second time: the repeated line adds nothing details docs
code/module-var-not-const ✓ file A var / val / use declaration at module level - only a constant lives there, an expression outside a method body is refused by the compiler and the apply rolls the project back docs
code/param-redeclared ✓ file A val, var or use in a method body with the name of the method’s own parameter: a method is one scope with its parameters, and the apply rolls the project back details docs
code/lambda-changes-outer-local ✓ file A lambda body assigns to a local or a method parameter it captured: the compiler refuses the whole project details docs
code/loop-header ✓ file Malformed ‘for’ loop header docs
code/invalid-string-escape ✓ file Invalid escape sequence in a string literal (\', regex-style \d) - the compiler rejects such a literal; valid are \н \в \т \\ \" \% \$ \ю<code> and the Latin spellings docs
code/dead-interpolation ✓ file A doubled interpolation sign before a brace: the platform reads the pair as an escaped sign, and the expression is never evaluated details docs
code/unused-local ✓ file A val, var or use variable the method never reads or only assigns: the name takes up room and misleads a reader details
code/unused-loop-var ✓ file The variable of a for X in loop that the body never reads; the counter of for X = A to B is not reported, as in the platform IDE
code/ref-field-needs-req ✓ file Structure reference field without ‘req’ docs
style/boolean-compare ✓ file Comparing a boolean value with True/False docs
style/boolean-ternary ✓ file A ternary with True and False branches: it equals its condition or the negation of it, and the platform IDE warns about it details docs
style/undefined-is ✓ file Checking Undefined with the ‘is’ operator docs
style/negated-is ✓ file Negating the ‘is’ operator on the outside docs
style/semicolon-line ✓ file ‘;’ not on its own line docs
style/wrap-operator ✓ file Operator at the end of a wrapped line docs
style/wrap-comma ✓ file Comma at the start of a wrapped line docs
style/camel-case ✓ file Name is not in UpperCamelCase docs
style/const-case ✓ file Constant is not in ALL_CAPS docs
style/exception-prefix ✓ file Exception name without the exception marker - a prefix on a Russian name, the Exception suffix on a Latin one
style/abbreviation-case ✓ file All-caps abbreviation in a name docs
style/enum-name-vid ✓ file Enumeration name starts with “Type” docs
style/collection-literal ✓ file Manual collection fill instead of a literal docs
style/constructor-literal ✓ file A constructor of a type that has a literal, called with constant arguments only: the platform IDE warns about it details docs
style/redundant-tostring ✓ file An explicit ToString() call in a concatenation docs
style/interpolation ✓ file Concatenation instead of interpolation docs
style/type-colon-space ✓ file Spaces around the type colon docs
style/union-spaces ✓ file Spaces around ‘|’ in a union type docs
style/nullable-shorthand ✓ file Undefined in a type without the ‘?’ shorthand docs
style/redundant-type ✓ file Redundant type annotation on initialization docs
style/redundant-scope ✓ file A scope that is the only statement of its block ends where the block ends and limits nothing details docs
style/optional-params-last ✓ file Optional parameter before a required one docs
code/resource-bare-name ✓ file Resource{Resources/<file>.svg} - the key is a path relative to the Resources folder; spelling that folder out breaks the lookup docs
query/named-parameter ✓ file A named parameter &Name inside a query literal - the literal takes its values by interpolation (%Name) docs
code/this-in-static-method ✓ file The keyword this inside the body of a static method - a static method is common to the whole type and has no object context, the compiler rejects the project docs
code/instance-call-from-static ✓ file A bare call of an instance method of the same owner from a static method - the docs forbid it outright; call the method on a value or make it static docs
code/close-in-before-close ✓ file Close() inside BeforeClose – the platform ignores the call and nothing closes the form afterwards
query/no-isnull ✓ file ISNULL( inside a query literal – the query language has no such function
style/abstract-name ✓ file An abstract variable name (Data, Item, Value) says nothing about the variable details docs
style/single-letter-name ✓ file A single-letter name of a variable, parameter or loop variable - per the names standard one-letter names belong only to short lambda parameters ((A, B) -> A + B) docs
style/negated-boolean-name ✓ file A boolean variable named from the negation (NotConnected, NoErrors): the name comes from the affirmative details docs
style/type-in-name ✓ file A variable name starting with a container type name (the Russian spellings of array, structure and map) - the type is visible from the declaration and the editor, keep it out of the name docs
style/numeral-in-const-name ✓ file A spelled-out numeral in a constant name (TIMEOUT_ONE_MINUTE) describes the value - name the constant abstractly (TIMEOUT) so a value change does not break the name docs
code/required-field-default ✓ file A structure or exception field marked req also has a default value, which the compiler rejects. The fix removes the initializer only when an explicit type remains.
code/declaration-needs-init ✓ file A union-typed local or optional field without an empty alternative has no initializer; a module constant (const) or a use variable has no value.
code/return-use-resource ✓ file A return hands out a use resource that closes when its scope ends, including casts, null coalescing and conditional expressions.
code/duplicate-when ✓ file A when branch of case repeats a literal, a local enumeration item or an explicitly named type handled earlier.
code/duplicate-catch ✓ file An exception type occurs more than once in the catch sections of one try statement.
code/duplicate-declaration ✓ file A name is declared twice where names are case insensitive, or an enumeration has more than one default item; exact method overloads and sibling local scopes remain legal.
code/captured-local-write ✓ file A mutable local or parameter of a named method is assigned after a lambda captured it: the lambda sees a value other than the one at capture details docs
comment/doc-tag-param ✓ file An @parameter tag against the signature below it: a name the method does not have or spells otherwise, a name described twice or out of order, a name the environment cuts (an underscore, a dot, a lowercase “ё”), a tag above a declaration without parameters. The parameters of a method are described all or none details docs
comment/doc-tag-result ✓ file An @returns tag above a method without a result, or a second one (the hover glues the texts); an @throws type the environment cuts at its first dot; either tag above a declaration that is no method details docs

Tier C rules in detail

code/self-assignment. A compound form is judged only when the file tells the operand type: a string joined with itself compiles. A plain one is removed by the fix.

code/assign-readonly. The rule also judges a val field of a structure, including one reached through a parameter or a local whose structure or exception type is declared in the same file. For a local the fix turns val into var.

code/unreachable-statement. An exit is also a call of a never method of the file and a branching where every branch ends. A case over every item of an enumeration of the file counts too.

code/ternary-and-or. A and X is String ? 1 : 0 reads as A and (X is String ? 1 : 0) and does not compile unless both branches are boolean. The plain A and B ? 1 : 0 takes the whole condition and is not reported. The fix puts the condition in parentheses.

code/duplicate-annotation. Annotations pile up until the nearest declaration, and a comment between them does not separate them.

code/duplicate-import. The short and the full name of the own project are one namespace, and the letter case tells names apart. The platform IDE warns about every repeat after the first. The fix removes the repeated line.

code/param-redeclared. Nested blocks belong to the same scope: a loop, a branch, a try. The compiler answers “a variable named X is already defined”. Loop and catch variables, lambda parameters and full-form lambda bodies are not judged.

code/lambda-changes-outer-local. Judged are a var variable or a parameter of the method or of an outer lambda, the operators =, +=, -=, *= and /=, a short or a full lambda at any depth. A member or an element of the captured value may change. A val, use, loop or catch variable is read-only and gets another compiler error.

code/dead-interpolation. %%{...} and $${...} look like this, and the value carries the text of the expression. Escape the first sign (\%%{...}) or build the string by concatenation.

code/unused-local. Names are resolved by block scope, as in the platform IDE. The fix drops the name of an unused use variable, and the resource is still closed at the end of the scope.

style/boolean-ternary. The rule judges a module, a string interpolation and a yaml binding. The fix writes the condition or its negation the way the platform binds not.

style/constructor-literal. An example: new Date("9999-12-31"). FindType with a constant name is judged the same way. The fix writes the literal where it holds the same value.

style/redundant-scope. The platform IDE warns about it. The fix removes the scope and moves its body one indent left.

style/abstract-name. An exact name is judged and so is a name with a digit tail (Data1). The list: Data, Item, Object, String, Value, Document, in either spelling. A stem inside a longer name (ClientData) and structure fields are left alone: a structure field is a serialization contract.

style/negated-boolean-name. Connected and HasErrors are the names to write. Judged only where the boolean type is proven: a type annotation or a boolean literal initializer.

code/captured-local-write. A write before the capture in a loop reusing the same binding is judged too. Earlier writes, a fresh local on each iteration and mutation of members or elements stay allowed. There is no automatic rewrite.

Tier D - semantics over stdlib, forms and the metamodel

Needs the project index and platform data: unknown types and objects, enumeration values, the execution model (client/server), form handlers, properties and queries.

Rule Scope What it checks
yaml/choice-needs-static-list ✓ file ValueChoice without a static ChoiceList docs
yaml/slot-needs-list ✓ file A slot the ui schema types as Array<...> holding a single component instead of a list: the apply refuses such markup, and the lint used to keep silent docs
yaml/value-choice-title ✓ file A ValueChoice with an explicit SwitcherDisplayKind: Switcher sets a Title: the platform does not draw it and the field stays unlabeled details
code/unknown-type ✓ project Unknown type
code/catch-non-exception ✓ file The type in catch is not an exception (a stdlib non-exception or a local structure) - the compiler rejects such code docs
code/unknown-member ✓ file A member access on a variable of a known stdlib type - plain or a generic, whose arguments type the members and do not name them - that the type does not have (first hop, typos get a hint)
code/member-kind-mismatch ✓ project A stdlib method read as a property (or the other way round) docs
code/unknown-static-member ✓ project A member reached through a type name that the type does not have (DateTime.Minimal()): such a call will not compile details
yaml/foreign-not-public ✓ project A yaml reference to an element of another subsystem whose VisibilityScope is neither InProject nor Global: it is unreachable from outside its own subsystem, and no import helps details docs
code/foreign-not-public ✓ project A module or a query names an element of another subsystem whose VisibilityScope is neither InProject nor Global: the compiler rejects the reference at that line details docs
code/call-arity-cross ✓ project A module call does not match its resolved signature: argument count or named-argument binding; ambiguous overloads and shadowed module names remain unjudged docs
code/missing-return ✓ project A typed method has a known path that reaches its end without return: along that path the method returns nothing details docs
code/unused-return-value ✓ file A standalone call discards the result of a platform method marked CheckValueUsage: the work of the method is thrown away details docs
code/ambiguous-type ✓ project A short type name in code refers to more than one visible project namespace details docs
yaml/ambiguous-type ✓ project A short type name in YAML refers to multiple visible project namespaces. Root and package names have equal priority; qualify the type with its namespace docs
code/undefined-name ✓ project Undefined name in an expression (a typo in a name) and in a short string interpolation ("?$format=json" substitutes the name format, \$ is needed) - the compiler rejects such code
code/unknown-object-type ✓ project Unknown project-object type
yaml/unknown-type ✓ project Unknown type in yaml
yaml/dynlist-missing-field ✓ project Missing dynamic-list field docs
yaml/dynlist-row-editing ✓ project An OnRowEdit handler on a list over a flat dynamic source: the platform never calls it at all details docs
yaml/dynlist-joined-table-param ✓ file A parameter (&Name) or a binding (=...) in the arguments or the filter of a joined table of a dynamic list: it is never evaluated and the list fails at runtime details docs
yaml/dynlist-filter-disabled ✓ project A dynamic-list filter declared with Use: False while the paired module enables it by assignment: the first frame shows the whole table details docs
yaml/dynlist-filter-computed-alias ✓ file A FilterItem of a dynamic list is named after the alias of a list field that is not a column under its own name - a computed field, a renamed column, a path through a reference: a filter reads the columns of the tables, so it silently goes by a column of that name or fails the apply details docs
yaml/list-form-needs-dynlist ✓ file A form inherits ListForm while the table in its content comes from an ArrayDataSource: the navigation item silently disappears details docs
yaml/ref-input-auto-commands – file A reference Edit with no Commands of its own: the platform draws its own button next to it, opening the value in a separate window details docs
yaml/toggle-command-pair ✓ file Two adjacent UsualCommand nodes with mirrored Visible (=X against =not X) emulate one command with two states, which the platform already has details docs
yaml/dynlist-column-sort-lost – file A column of a table over a dynamic list whose value is a call: the platform sorts by the field of the source, so that header will not sort details docs
yaml/badge-column-image ✓ file A StandardTableColumn with Kind: Badge also sets Image: the platform does not show the picture details docs
code/unknown-enum-value ✓ project Unknown enumeration value docs
yaml/enum-needs-nullable ✓ project An enumeration in a type position without ?: it has no default value, so the server-side compilation fails details docs
yaml/enum-default-value ✓ project The DefaultValue of an enumeration-typed field must be the bare name of a declared value: the type-prefixed spelling (LabelVisibility.Invisible) or an unknown name is rejected by the build docs
yaml/unknown-enum-value ✓ file A component property value outside the enumeration of the ui schema (ContentVerticalAlign: End - the vertical axis has Top, Center, Bottom, Baseline and no End)
yaml/bare-object-value ✓ file A bare word on a property that accepts Object - the platform expects a quoted literal, an = binding or a $ localized-string reference docs
code/unknown-resource ✓ project A Resource{...} reference is unknown, hidden or ambiguous at the winning namespace priority docs
form/unknown-handler ✓ project Form handler not found in the module docs
form/handler-signature ✓ project Handler signature does not match the event docs
code/bound-handler-annotation ✓ project The @Handler annotation on a method the paired yaml binds to an event, a command or a route: the annotation marks an override, and the compiler refuses it on a bound method docs
code/handler-overrides-nothing ✓ project The @Handler annotation on a method that the paired yaml does not bind and that overrides no handler the module’s base declares in the project’s compatibility mode: the compiler refuses it. For an interface component the lists come from the component descriptions the distribution ships, for the other modules (an object, a record set, a record, a scheduled job, a command) from the handler providers of the compiler; a module that takes handler names from the element’s own description at build time is not judged, the own module of an element with access settings is judged by them, OnCreateOnBasis by the CreateOnBasis list of the description, and the module of the project by its kind details docs
code/mandatory-handler-missing ✓ project A handler the compiler requires and the module does not declare: the handler of a command and of a scheduled job, the computation of the client work parameters, the permissions handler of an action privilege, OnCreateOnBasis for each type CreateOnBasis lists, the access handlers the settings use and the pair of a declared navigation link handler. The build refuses the module with “Mandatory handler X is not defined” details docs
code/unknown-form-component ✓ file Access to a component the form markup does not declare docs
code/server-call-from-handler ✓ project Server method is unavailable to a client handler docs
code/image-binding-server-call ✓ project A platform component’s Image property reaches the server directly or through client methods details docs
code/computed-property-server-call – project Computed properties reach a client-available server method without the standard result cache details docs
code/sequential-server-calls – project A client method on the opening path calls the server several times in a row, where one server method with a typed result would make a single trip details docs
code/resource-read-without-cache ✓ project A method available from the client runs on the server and only returns the text of a resource, read without the standard result cache details docs
code/client-annotation-in-server-module ✓ project Client annotation in a server common module docs
code/client-module-in-http-service ✓ project Client common module in a server environment docs
code/server-annotation-in-client-module ✓ project Server annotation in a client common module docs
code/query-needs-server ✓ project A Query{...} block in a method of a client-side module with no @OnServer: the type does not exist on the client and the compiler rejects the build details docs
code/local-method-cross-component ✓ project Cross-component call of a local method docs
code/local-method-cross-module ✓ project Cross-module call of a local method docs
naming/yo ✓ file The letter yo in a name docs
naming/underscore ✓ file Underscore in a name docs
naming/abbreviation ✓ file All-caps abbreviation in a name docs
naming/latin-term ✓ file English term spelled in Cyrillic docs
naming/enum-vid ✓ file Enumeration name with the word “Type” docs
naming/kind-in-name ✓ file Element kind inside its name docs
naming/filler-word ✓ file Filler word in a name docs
naming/module-suffix ✓ file Environment suffix in a common module name docs
naming/number ✓ file Wrong number for the element kind docs
naming/boolean-name ✓ file Boolean attribute name docs
naming/presentation ✓ file Element presentation docs
naming/prefix-by-kind ✓ file Kind-specific name without its prefix docs
code/unknown-ns-object ✓ project Unknown object in a kind namespace
query/unknown-table ✓ project Unknown table in a query docs
query/in-subquery-composite ✓ project ‘IN’ with a subquery over a composite type docs
yaml/unknown-property ✓ file Unknown object property
code/reserved-name ✓ file A reserved name: the type keyword in either language as a structure field or a parameter. The server apply refuses all three spellings details
yaml/builtin-property-name ✓ file Built-in property name clash
yaml/auto-bare-value ✓ file A bare Auto in a property whose type is the union of Auto and a string (the caption of a button, the presentation of a filter of a dynamic list): the apply refuses the value as one whose type is not specified details
yaml/property-shadows-module ✓ project A component property named after a common module: the name hides the module across the component, Module.Method() reads as a member of the property value, and the apply fails details docs
yaml/size-needs-no-stretch – file A size without disabling the stretch docs
yaml/col-width-needs-no-stretch – file A Width on a table column - a number or a binding - without HorizontalStretch: while the column stretches the number acts as a share of the free space rather than pixels details docs
yaml/matrix-group-max-width – file A numeric MaxWidth on a group that lays out as a matrix: a phone draws the page at desktop width and the content runs off the right edge details docs
yaml/card-literal-stretch-weight – file A literal StretchWeight on a card or on a group inside one: in the mobile layout Safari collapses the card and Chrome shows nothing details docs
code/unused-method – project A method declared in the project and used nowhere else – not by a call in code, a yaml binding or a name in a string. A comment is not a use details
code/unused-constant – project A module constant referenced nowhere else in the project: the declaration is left with no work details
code/duplicate-method-body – project A method body of at least five lines repeated word for word in another file: the normalized body is compared, and a change goes into both copies details
yaml/missing-import ✓ project A yaml reference to a public element of another subsystem whose namespace the Import section does not list: the short name does not resolve details docs
code/unused-import ✓ project A module imports a subsystem or one of its packages, and the compiler never looks up a type in that namespace details docs
code/missing-import ✓ project A module names a public element of another subsystem without an import line for its namespace: the project fails to compile at that line details docs
yaml/wrong-namespace ✓ project A qualified name of this project in a yaml value leads to a namespace where no element of that name lies: the compiler answers “Unknown type” details docs
code/wrong-namespace ✓ project The same in a module or a query: a name of this project leads to a namespace where its element does not lie, and the compiler answers “Unknown type” details docs
code/package-resources-missing ✓ project ResourcesPackage.Current() in a module of a package or at the root of a subsystem that has no Resources folder of its own: no file is found, and that breaks only at run time details docs
code/resource-replace-absent – project A replacement of a string that the text of its resource file does not have outside comments: the replacement changes nothing, the label was renamed in the file or the code details
code/resource-label-unfilled – project A label of a resource file that the complete chain of replacements leaves in place: the page gets the label instead of a value details
yaml/missing-subsystem-usage ✓ project Elements and modules of a subsystem import another subsystem while the description of their own does not list it under Using: the project fails to apply details docs
yaml/computed-binding-assigned ✓ project Every instance of a component binds a property with a computed expression while the component assigns that property in its own module: the platform crashes on the assignment details
yaml/localization-missing-import ✓ project An unqualified $Dictionary.Key whose dictionary lies in a namespace this yaml does not import: the apply refuses the node details docs
yaml/presentation-field ✓ file The presentation field of an object docs
yaml/unexpected-type-argument ✓ file A type argument on a property the ui schema declares without one: that is another type, and the build apply rejects it details docs
yaml/property-since-compat ✓ project A component property newer than the project’s CompatibilityMode (the ui schema records the version it appeared in) - apply rejects it as an unknown property. A project description that declares no supported mode is read in the newest mode, as the platform reads it docs
query/deletion-mark-immediate ✓ project A deletion-mark condition in a query on an object whose DeletionMode is Immediately - such an object has no mark and the query fails on apply docs
code/load-object-unwrap ✓ file A force-unwrapped LoadObject() result on a reference from another record or a tabular-section row: the record may have been deleted physically, and the unwrap fails the whole pass details docs
yaml/item-id-required ✓ file A metadata collection item (an attribute, a tabular section, an enumeration item, an access-key parameter) without the Id its class declares - apply answers ID required
code/unknown-row-field ✓ project A field addressed on a dynamic list row (DynamicListRow<Form.Type>) that the list’s Fields do not declare docs
code/row-field-null ✓ project A row field that may be Null goes where the declared type refuses it: a dynamic list field taken through a reference (Owner.Number) into a typed structure field, or a Query{...} column read through a reference or from the joined side of an outer join into a structure field, a parameter, a variable or a method result (a ? type refuses it too). The compiler answers Null cannot be assigned docs
yaml/unknown-attribute-property ✓ file A key an attribute’s own metamodel class does not declare (Length on a regular attribute - the built-in Code declares it, a Number attribute has IntegerPartLength) - apply rejects the object
yaml/empty-group-sized ✓ file An empty Group with Height/Width (a literal – always; an =... binding – only without a Name) – the renderer drops the node and there is no gap
yaml/insert-row-needs-align ✓ file A horizontal group with no ContentVerticalAlign lines its children up on the baseline, and an HtmlContainer insert, a button and a picture break that line details docs
yaml/component-row-needs-align ✓ project The same button and picture, when a project component draws a neighbour: the two stand at different heights details docs
yaml/hint-too-long ✓ file A Tooltip longer than the render limit – the tail is not shown at all
yaml/popup-in-markup ✓ project A PopupComponent placed in the yaml markup: the content is drawn right in the form flow before the window ever opens details docs
yaml/date-input-needs-plain-date ✓ file Edit<Date?> – the renderer silently drops a date input that allows the empty value; make the type plain and express “not set” with the empty date docs
yaml/binding-needs-auto ✓ project A binding of a plain component property calls a method declared nullable - the client registers an “unexpected Undefined value” error on every recomputation; “not set” is the Auto value
yaml/double-quoted-binding ✓ file A binding of a nonstring component property in double quotes - the server rejects a quoted value there; a bare value or single quotes compile
code/client-available-needs-context ✓ project @AvailableFromClient on a method of an interface component module that is neither static nor @Contextual – the component type is not a singleton, so the apply rejects the modifier docs
code/client-available-unused – project A method declared @AvailableFromClient with no client place in the project naming it: the annotation opens a surface to the client that nobody uses details docs
code/server-module-in-client-context ✓ project A Module.Member(...) access to a common module with Environment: Server from a method that runs on the client: the type does not exist on the client details docs
code/component-in-server-context ✓ project A Component.Member(...) access to an interface component from code compiled for the server: the component’s type lives on the client details docs
yaml/delete-current-needs-immediate ✓ file OnReferencedObjectDeletion: DeleteCurrent on an attribute of an element that only marks a deletion: the compilation rejects that pair details docs
code/access-context-read-noop ✓ project Extending the access context with the read privilege for a type whose yaml says Read: PermitEveryone: there is nothing to grant, and the call only looks like a guard details docs
code/per-object-permissions-need-common ✓ project An object calculates its permissions per object, but its module declares no ComputeAccessPermissions handler – the common calculation is required even then, if only to return an empty array. Only without the handler lists of the data: with them code/mandatory-handler-missing reports the same handler as an error docs
code/permission-field-not-declared ✓ project Inside ComputeAccessPermissionsForObjects a field outside ComputePermissionsBy is read, or a declared field is reached through Entity instead of the record docs
code/permission-handlers-need-recalc ✓ project A module declares a permission handler while nothing calls RecomputeAccessPermissions for that entity: the platform never calls the handler, so a permission edit silently does nothing details docs
code/access-key-handler-flavour ✓ project A computed access key requires the CheckHasAccessKeys handler in its manager module; a key with ManualGrant: True cannot declare it docs
code/permission-right-not-computable ✓ project A ComputeAccessPermissions handler grants a permission the entity’s yaml does not declare computable: the build applies, and the permission recomputation fails at runtime details docs
yaml/placeholder-key-in-strings ✓ file A key carrying the placeholder $0 in the Strings section of a LocalizedStrings dictionary: the section compiles to a method without parameters details docs
yaml/localization-ref-to-template ✓ project A $Dictionary.Key reference pointing at a key of the Templates section: a reference resolves against Strings alone, and the apply fails details docs
code/compare-with-localized ✓ project A localized value (Dictionary.Key(), Presentation()) compared against a literal or against a second localized value – in another language the branch simply never runs docs
code/url-params-partial-encoding – file A call of the Url method WithRequestParameters: it encodes a parameter value only partially, and a value that is itself an address arrives cut at its first “&” details docs
code/url-data-scheme ✓ file A data: address passed as a literal to the Url constructor: the constructor parses it as a path, and a picture fed the result draws nothing details docs
code/bound-property-assign ✓ file A property computed by an expression in the paired markup is assigned from code: the platform refuses such an assignment details
yaml/event-needs-importance ✓ file An EventLogEvent description that does not set Importance: its default demands the value in every constructor, and one omission fails the apply details docs
yaml/event-property-type ✓ file An EventLogEvent property type outside the platform’s closed list: the refusal comes only from the server-side compilation and costs the deploy details docs
code/collection-field-needs-req ✓ file A structure field has a known platform type without a default value and no req, nullable marker or initializer details docs
code/var-needs-init ✓ project A variable declared by type alone where the type has no constructor and no default value (var Response: HttpResponse) details docs
code/unknown-tabular-member ✓ project A member access on a tabular section’s row collection that the array type does not have: the collection is Array<Entity.Section> details
code/global-unavailable ✓ project A call of a global name outside its environment: Message in a server module, the dynamic evaluation globals in a client method without @OnServer details docs
code/type-unavailable ✓ project A standard type used where its documentation says it does not exist: a server-only type such as Encodings in a client method, and the reverse docs
code/constant-unavailable ✓ file A module constant read by a method compiled for an environment the constant does not exist in: a constant of a form module without an annotation lives on the client, and an @OnServer method of the same module does not see it. The quick fix gives the constant the missing side details docs
code/module-type-unavailable ✓ file A structure, an exception or an enumeration of the module used by a method compiled for an environment the type does not exist in: a type of a form module without an annotation lives on the client, and an @OnServer method of the same module can neither declare, create and catch it nor read an item of it. The quick fix gives the type the missing side details docs
code/qualified-member-unavailable ✓ project Module.NAME of a common module of both environments whose constant, structure or enumeration exists on one side only, used by a method compiled for the other one details docs
style/shadow-project-name ✓ project A variable, parameter or method named like a project element: the declaration shadows the element for that scope details docs
style/shadow-own-property ✓ project A val, var or use variable named like a property of the object its method works on: the name resolves to the variable, so neither a read nor an assignment reaches the property details docs
style/redundant-union-member ✓ file A member of a union type that another member already covers: a repeat, a second empty value, or a member under a wider neighbour details docs
code/unclosed-resource ✓ file A closeable resource abandoned by an early exit from the loop over it: a return or a break in the middle leaves it open details docs
code/use-needs-closeable ✓ file The use modifier over a type the catalog describes and that does not inherit Closeable - the modifier exists for the automatic Close(), and the compiler refuses the declaration docs
conventions/untranslated-visible-literal ✓ project Visible text left as a Cyrillic literal where the project already references the same property into a localization dictionary details
conventions/untranslated-code-literal – project Visible text left as a Cyrillic literal in a module: judged by the sink it reaches details
conventions/missing-translation – project A project token or a Cyrillic comment line the project’s translation dictionary does not cover yet details
code/procedure-as-value ✓ project A resolved procedure call is used as a value details
code/contract-parameter-name ✓ project An implementation parameter name differs from its project contract details
conventions/platform-translation-shadow ✓ project A project declaration blocks a platform translation without an explicit dictionary pair details
code/unknown-structure-field ✓ project A field access on a structure declared in the project is checked against its declaration: a renamed field turns red at its reader rather than on the server apply details
code/redundant-skip-undefined ✓ file SkipUndefined() on a collection whose known element type is not nullable details docs
code/redundant-cast ✓ project A cast to a type the operand already has: the platform IDE warns about such a cast details docs
code/cast-to-non-null ✓ project A cast that only drops Undefined: the operand is T? and the cast names T, where the platform IDE advises the non-null operator details docs
code/redundant-undefined-guard ✓ file A ??, ! or ?. over a value whose type has no Undefined: the guard checks nothing and the default is never used details docs
code/redundant-type-check ✓ project A check X is Type whose result the type of X decides: the check always passes and is not never does details docs
comment/unknown-name – project A name in a comment that neither the project nor the platform has: a renamed method, a replaced object, a typo details
comment/doc-tag-target ✓ project An @see reference written as a name or a chain of names that leads nowhere, and an @throws type neither the project nor the platform declares; the finding lists what the method body throws details docs
code/deprecated-api ✓ project A call that binds only to a deprecated form of a platform method, as the platform IDE warns details docs
code/deprecated-project ✓ project A use bound to a project method, property, constructor, parameter or enumeration value marked deprecated, as the platform IDE warns docs
code/contract-method-not-abstract ✓ project A non-abstract method, ordinary or static, in a module of an entity contract - of the contract itself, of its object or of a row: these modules take abstract methods only, and the compiler refuses any other with “Non-abstract method … cannot be defined” details
code/client-pattern-unicode-class – project Unicode class p in a literal client Pattern; enable only after confirming the target client rejects it details

Tier D rules in detail

yaml/auto-bare-value. The refusal of yaml/hierarchy-bare-value is not particular to the hierarchy: a property whose type is the union of Auto and a string reads a bare Auto as neither. A probe on a live server got “the type of the value is not specified” for the caption of a button (a component property of the ui schema) and for three members of a dynamic list - the presentation of a filter group, of a filter item and the ascending sort presentation of a field’s automatic filter. The rule walks the markup with types: a node is typed by its own Type or by the member type its parent declares for its key (a component property from the ui schema, any other member from the type catalog); the source of a list takes the first generic argument of the list, and a property’s default value the type the property declares. Judged is a union of exactly Auto and String: Visibility: Auto of a union with a boolean is the Auto the union names, and UsedHierarchy stays with its own rule. A quoted word is text and a project component is not typed. There is no fix: whether the author meant the default value or the word as text is not in the file.

yaml/value-choice-title. Put the caption into a separate Label next to the switcher. A node without an explicit kind and a node with an Array<...> type argument, that is a checkbox group, are left alone.

code/unknown-static-member. The type of such a call carries on to the next hop of the chain. A bare name is read as a type only when the project gives it no other meaning. The module’s paired yaml counts even in a single-file check.

yaml/foreign-not-public. A reference is a type position, a FormType navigation target, the root of a binding chain =Module.Method(), a table of a list (of a dynamic list or of the reference input settings of a field) and a qualified Subsystem[::Package]::Element name. The qualified form resolves by the subsystem or the package it names.

code/foreign-not-public. Judged are a written type position, the root of a Module.Method() chain and a table of a query: a Query{...} block or the .xbql of a virtual table. The qualified Subsystem[::Package]::Element form belongs here too. Neither an import nor an @InProject annotation on the method helps. The project module belongs to no subsystem, so every non-public element is foreign to it.

code/missing-return. A complete case over an enumeration and a call of a never method count, while a loop guarantees no return. A project-scope check reads enumerations and signatures, and unresolved cases are left unjudged.

code/unused-return-value. The receiver type tells an immutable operation from a mutable namesake, and a short expression lambda is not a statement. Freshly extracted metadata is needed. There is no automatic rewrite.

code/ambiguous-type. The subsystem root has no priority over its packages, so the namespace is written out. Explicit qualifiers and file-local type declarations are respected.

yaml/dynlist-row-editing. The event is declared for the node rows of a hierarchy. On a flat list a click opens the object’s automatic form, so give the object an object form of its own.

yaml/dynlist-joined-table-param. On the main table the same entry is legal, and on a joined one the compiler stays silent about it. Keep a literal in the yaml and assign the live value from code: Source.JoinedTables[i].Arguments.

yaml/dynlist-filter-disabled. That is the first-render race: the platform draws the list without waiting for the code. Declare the filter enabled, with an empty value.

yaml/dynlist-filter-computed-alias. A filter looks its Field up among the columns of the main and the joined tables, not among the fields of the list, while sorting does take an alias. A column path under another name is no exception: on a live server a filter by the alias of the field T.Article (ArticleT) and of the path T.Group.Description (GroupName) failed the apply exactly like a computed alias, while the same path aliased after an existing column applied: the lookup found the table’s own column of that name. A column under its own name (T.Article aliased Article) is what the filter finds and is not judged; neither is a two-part path whose last part is the alias when one of the tables has no Alias - its first part may be that table. For a column path, name the path in the filter (Field: T.Article, Field: T.Group.Description - both applied). To filter by the computed value, use a FilterItemExpression with the expression of the field and switch it on with a binding of Use; when the column is meant, name it with the table alias.

yaml/list-form-needs-dynlist. The list-form skeleton is built around a dynamic-list table, and the content holds not a single type with DynamicList. Give the table a dynamic list, or inherit a plain form (Type: Form).

yaml/ref-input-auto-commands. For a reference input Auto unfolds into a command-interface fragment. The button is usually wanted, so the rule is informational and off, and an empty fragment silences it.

yaml/toggle-command-pair. A SwitchableCommand carries the representations and images of both states, the initial Active is a literal, and the platform owns the state. A shared handler strengthens the case but is not required.

yaml/dynlist-column-sort-lost. Bind the column to the field, or add a presentation field to the list itself. A column with DisableSorting: True is not judged: it has no sorting by declaration. Off by default, because whether that column was meant to sort is not visible from the file.

yaml/badge-column-image. The value is drawn as tag pills, and the picture is documented only for Kind: Picture. Drop Kind and the picture stands next to the value text, or set Kind: Picture.

yaml/enum-needs-nullable. Both spellings are judged: the input field is recognized as Edit<...>, the platform’s own English. InputField is no spelling of it and falls to yaml/unknown-type. A write or delete parameter is left to yaml/union-needs-nullable: there the empty value is required of any type, even an enumeration with a default item, and that rule quotes the refusal of the section.

code/image-binding-server-call. Methods with enabled or unknown caching and client variants are excluded. Pass the image with the data, or take it from client data already loaded.

code/query-needs-server. A client-side module is a form module and a common module whose Environment involves the client.

code/reserved-name. The rule judges a structure field and a method parameter. The capitalized spelling is confirmed by a live apply on the server.

yaml/property-shadows-module. The apply answers with an unknown-method error and the stand rolls back. There is one cure: rename the property. There is no autofix, because the name is written in the markup, in the paired module and outside the component as well. Only a common module is judged, and only one reachable by the bare name: the component’s own subsystem, its root and its packages, or a namespace its yaml imports. Subsystem brings the modules at the root of that subsystem, Subsystem::Package those of the package. A namesake catalog or component is a live idiom.

yaml/col-width-needs-no-stretch. All three column kinds are judged, and a width given by a binding too: it yields a number at run time. The column comes out wider than asked and the content drifts away from its neighbour. A pixel width needs HorizontalStretch: False, and a share with a guaranteed minimum needs MinWidth. Off by default: width-as-a-share is a legitimate technique, statically indistinguishable from the trap.

yaml/matrix-group-max-width. The maximum doubles as the available width, so the automatic columns are laid out by it rather than by the window. The answer is Auto. Off by default: a desktop-only page lives with a maximum fine.

yaml/card-literal-stretch-weight. The weight is a flex with a zero basis, and in a vertical column, that is in the mobile layout, the basis applies to the height. Safari clips the card with the rounding. On a phone drop the weight through a binding. Off by default: a card living only in a wide row keeps it legitimately.

code/unused-method. A name inside a string literal counts as a use: an HTML insert calls the method by name, and such a call is invisible to static reading. A comment counts nowhere – not in the module that declares the method, not in the yaml paired with it, not in any other element; when a comment is the only place the name turns up, the finding says so. Never judged: a handler the platform calls by name, in either spelling (the handler lists of the data and the record-level security handlers), an object module, a module paired with an HTTP service, and a method whose annotation names a caller outside the project code (@Handler, @Subscription, @Implementation and the rest) – that annotation is the answer for a method the platform or a contract calls itself. For a call that stays invisible anyway – a name assembled at run time, a client entry point kept on purpose – freeze the finding in the baseline with its reason (--write-baseline, then --baseline). Off by default: over a subset of the files a method used outside it would look dead.

code/unused-constant. Words in code, yaml, strings and comments count as uses, and the translation dictionary does not. Global constants and constants with unknown annotations are skipped. Enable the rule for a whole-project check.

code/duplicate-method-body. Normalization drops comments, blank lines and indentation. A platform hook is told apart by its @Handler annotation rather than by a list of names: the same hook body in every object is normal. Copies inside one file are not judged. Off by default: whether two copies should become one method is a design decision.

yaml/missing-import. A reference is a type position, a FormType navigation target and the root of a binding chain =ForeignModule.Method(). What is needed is Subsystem for an element at the subsystem root and Subsystem::Package for one in a package: importing the subsystem does not bring its packages. An import in the paired module does not cover the markup. A binding root is judged after subtracting everything that explains the name on its own: the declarations of this yaml, of the paired module and the implicit platform names. The tables of the paired query of a virtual table resolve against the same section and are reported on it: the .xbql and every item of its FROM lists, the one after a join condition included. Qualified and temporary tables are not judged. So do the tables of a dynamic list, that is the Table of its MainTable and of each of its JoinedTables, and the JoinedTables of the reference input settings of a field; the finding sits at the value of the table, and a qualified table needs no import.

code/unused-import. The platform IDE reports such imports. What counts is what the compiler resolves: a written type; a name that is neither a local nor declared by the module or the paired yaml; the root of a chain Root.member, even when the root is a property of the paired yaml; a qualified name; a table of a query; an enumeration value in a when branch; a bare Resource{...} key whose file only that namespace holds. The types that values bring along count as well: the properties of the paired yaml the code names, the results and fields of other elements reached through a chain, the fields of those structures, and a query column that passes a field on. The import line itself, a member after a dot and a local named like an element are not uses, so import Subsystem next to import Subsystem::Package is reported when the module reaches only the package. A reference from the paired yaml is not a use either, since the yaml has an import section of its own. An import of the module’s own namespace is judged the same way. The fix removes the line.

code/missing-import. What is needed is import Subsystem for an element at the subsystem root and import Subsystem::Package for one in a package: importing the subsystem does not bring its packages. Judged are the written type positions (a parameter, a variable, a return, new, as, is, a Type<...> literal, generic arguments), the root of a Module.Method() chain and the tables of the Query{...} blocks, every item of a FROM list included. For a root everything that explains the name on its own is subtracted first: the declarations of the method and the module, the implicit names of the platform and the sections of the paired yaml. The project module belongs to no subsystem and needs the import for every element it names, at the root of a subsystem as in a package.

yaml/wrong-namespace. Judged are the full Vendor::Project::Subsystem[::Package]::Name and the partial Subsystem[::Package]::Name, while the project declares the element elsewhere. The usual cause is a move of the element between the root of a subsystem and a package: a generated list form keeps its row type spelled by the old place. Every string value of an element and of a descriptor is read, the namespace lists (Import, Using) and resource references aside. A name of another project, a type declared in a module and a chain that spells a namespace whole are not judged. A partial name is judged when its first segment is a subsystem of the project that no declared library names as well. When the element lies in one place, the finding carries the fix: the namespace is replaced by the placement of the element. An element in several places is reported with its places and no fix.

code/wrong-namespace. The name comes full or partial, and it may stand in a type position, in a call or as a table of a query. For a table the compiler answers that the table is not found. The import line and the key of a Resource{...} literal are not read. The fix replaces the namespace when the element lies in one place.

code/resource-replace-absent. It looks like Resource{card.css}.OpenReadableStream().ReadAsString().Replace("{{SIZE}}", Size) when the file has no {{SIZE}}. The rule follows the text of one resource file through the chain of Replace calls: across locals, wrappers over the read (by a path, a path inside a folder or a parameter of type Resource), text helpers, and maps filled from a literal list of paths, client parameters included. Each step is applied to the file with its comments blanked. The message says when the string is only in a comment of the file, or when an earlier step of the chain has already replaced it. A helper that serves several files is not blamed for one of them. A computed path or search string and a choice between two files are not judged.

code/resource-label-unfilled. A label is a word between the delimiters the chain uses for its own strings: {{A}} and {{B}} give {{NAME}}. The label is judged when the chain is complete, that is when nothing replaces further in a caller, in a callee or through a variable. A part of the file (Substring, a wrapper that keeps the inner part) and a value that another branch fills from elsewhere are not judged. The finding sits where the text leaves the chain. When the same chain also replaces a string the file lacks, both messages say it: that is what a renamed label looks like.

code/package-resources-missing. The method returns the resources of its own namespace alone, so for a package not even the files of its subsystem are found, and for the root not the files of its packages. The answer is one: ResourceNotFoundException, GetAll() included. In a package a Resource{...} literal does find the files of the subsystem. The folder is looked up on disk, and the project module is not judged.

yaml/missing-subsystem-usage. Subsystem::Package counts as an import of that subsystem, and all of it is learnt at deploy time. An import gives the short names, but it is Using that permits the subsystem, its packages included. A subsystem without a description has nowhere to declare the usage and is not judged. The diagnostic sits on the subsystem description, where the fix goes.

yaml/computed-binding-assigned. The platform answers with an IllegalStateException. A named argument is not an assignment, and a code-built instance, a bare-path binding, a literal or an unbound instance make the assignment legal: the rule fires only when every instance is bound computed.

yaml/localization-missing-import. What is needed is Subsystem for a dictionary at the subsystem root and Subsystem::Package for one in a package: importing the subsystem does not bring its packages. The apply refuses the node as a not-imported namespace. A dictionary of the yaml’s own subsystem, at its root or in a package, needs no import, an import in the paired module does not cover the markup, and the qualified $Subsystem::Dictionary.Key form needs no import.

yaml/unexpected-type-argument. An example: a form’s AdditionalCommands takes CommandInterfaceFragment, not CommandInterfaceFragment<UsualCommand>. An English tree is judged the same way: the key, the component, the property and the type head are canonized, and the argument is compared with the default name by name in either spelling.

code/load-object-unwrap. The shape looks like Row.Service!.LoadObject()!. A physical deletion comes from DeletionMode: Immediately and from the deleted-items form. Check the result for Undefined. The query row’s own .Reference is not judged.

yaml/insert-row-needs-align. An HtmlContainer insert carries a baseline of its own, so the element holding it slides down: 50 px on a live row. The nearest horizontal ancestor answers, and a row whose inner strip is already aligned stays silent. A Button keeps the baseline on its caption and a Picture on its bottom edge, so a captioned button next to a picture sinks by 19 px. ContentVerticalAlign: Center cures it. A layout binding counts in its statically horizontal branches. The pair is judged when one of the two is shown unconditionally or both are shown under the same conditions. Two neighbours with different conditions of their own, and a child that sets its own vertical alignment, are left alone.

yaml/component-row-needs-align. The component shows a native Button or Picture unconditionally, or picks between them by its own property: the instance sets the property to a literal, and the condition compares it directly or through a method that only returns that comparison. The button sank 19 px on a live row. Set ContentVerticalAlign: Center on the row. Visibility is read as in yaml/insert-row-needs-align. A component the rule cannot read statically takes no part, and a row the file rule judges alone is left to yaml/insert-row-needs-align.

yaml/popup-in-markup. A project component transitively inheriting PopupComponent is judged the same way. The platform has no property restricting the drawing to the window, and hiding it through Visible breaks the window itself. Build the window in code on every opening: a new PopupComponent(...), then OpenInPopupWindow().

code/client-available-unused. A client place is a module of the client environment, a client method of a server module, a yaml and a string literal. Off by default, like code/unused-method: a client call is not always visible statically.

code/server-module-in-client-context. Such a place is an interface component, a command and a client common module.

code/component-in-server-context. Server code is an @OnServer method anywhere and an unannotated method of a server or client-and-server module. The server compilation refuses with “Variable X is not defined”.

yaml/delete-current-needs-immediate. Marking is DeletionMode: DeletionMark, which is also the default. Not every kind carries the property: a register has none, and the rule leaves a register alone. The line Action DeleteCurrent cannot apply to object with a "DeletionMark" comes from the compiler, not from the documentation.

code/access-context-read-noop. Everyone may read such a type already. With that privilege alone the whole line goes; among others, only it does.

code/handler-overrides-nothing. The handlers of an interface component module are listed by the description of each component in the distribution, and a component inherits those of its bases. The other modules have no such description: the compiler declares their handlers in code, one provider class per kind of element, and the extractor reads that code to the terms the names are built from. So the object module of a catalog overrides BeforeWrite, AfterWrite, BeforeDelete, AfterDelete, OnFill, OnCreateCopy and, once for each type its description lists under CreateOnBasis, OnCreateOnBasis, the record set of a register BeforeWrite and AfterWrite, the module of a scheduled job Handler, the module of an access key CheckHasAccessKeys, and the own module of an element with access settings (a catalog, a document, a register, an HTTP service and the like) ComputeAccessPermissions. A module is matched to its element by the file name: Stock.yaml pairs with Stock.xbsl (the element’s own module) and with Stock.Object.xbsl, Stock.RecordSet.xbsl, Stock.Record.xbsl. Some modules take handler names from the element’s own description while the project is built: the operations of a processing, the operations of a SOAP client from its WSDL. Any name may be a handler there, and such a module is not judged. The own module of an entity takes one name that way too, the record-level security handler, and is judged all the same. Its kind tells which of those handlers it declares (ComputeAccessPermissionsForObjects for a catalog, ComputeAccessKeysForRead and ComputeAccessKeysForUpdate for an accumulation register or a periodic information register), and its access settings (AccessControl) tell which of them and of ComputeAccessPermissions the build uses: ComputeAccessPermissions once a privilege is PermissionsComputed or PermissionsComputedForEachObject, the record-level security handler once one is PermissionsComputedForEachObject, neither on the standard permissions of a settings storage. A handler the element declares but its settings leave off is refused with a message of its own, Handler "X" is not used in this project item, and the finding quotes it. The own module of an HTTP service, a SOAP service and a processing declares ComputeAccessPermissions alone and is judged by the same test of its AccessControl; below the mode a processing got its access settings in, the build does not read them, and the handler is not judged. A catalog, a document, an exchange plan or an integrable application whose description lists no type under CreateOnBasis declares no OnCreateOnBasis, and the finding names the property. A module the compiler declares nothing for - a common module, a data journal, a command interface fragment, a global client event - is judged too: any name is refused there. The module file of localized strings is not judged: the build does not compile it at all, and a probe on a server reported nothing written in it. The module of the project (Project.xbsl beside the project description) overrides ComputeSystemAccessPermissions in an application, and nothing in a library or an extension (ProjectKind). A kind the data does not list is not judged, and without the lists the rule is silent.

code/mandatory-handler-missing. The handler providers of the compiler build some handlers required, and a module that does not declare one is refused with Mandatory handler "X" is not defined - at the first line of the module, or at the first line of the description when the element has no such module at all. The extractor keeps the mark in the data, and a probe on a server gave that answer for every source the rule reads. Required wherever it is declared: Handler of a command and of a command with a component (a switchable command does not require it), Handler of a scheduled job, ComputeClientWorkParameters, AfterConnection of a self-registration parameter and ComputeAccessPermissions of an action privilege. OnCreateOnBasis of the object module is required once for each type CreateOnBasis lists: a module with fewer overloads than the list has types is refused as well, and the overloads are counted only while none of them takes a union of types. The access handlers are required exactly when the access settings use them - the access-control provider builds each with one value for enabled and required: ComputeAccessPermissions once a privilege is computed, the record-level security handler once one is computed for each object. A handler built with requiredHandlers needs its pair: a module that declares ComputeExternalNavigationLink has to declare ComputeReferenceByExternalNavigationLink, and the other way round. A method of the required name without the @Handler annotation gets another answer, Handler method "X" is not marked with annotation @Handler: the finding quotes it, and the fix adds the annotation. An access key is not judged, since a key granted by hand (ManualGrant) declares no handler in the newer modes. A module with a syntax error, a module the run leaves out while the disk has it and settings that cannot be read are not judged either, and without the lists of the data the rule is silent.

code/permission-handlers-need-recalc. The handlers are ComputeAccessPermissions and kin. A recompute with a non-entity receiver, the documented loop form, stands the rule down. Kinds with no recompute method, that is rights elements, are not judged.

code/permission-right-not-computable. ...ForObjects is judged too. Computability is declared by PermissionsComputed and PermissionsComputedForEachObject, explicitly or through Default. The recomputation answers that the permission is not marked as computed. Permissions are collected only from new AccessPermission(...) constructors in both namespaces, Entity.Privilege.* and HttpServicePrivilege.*, transitively over project calls: delegation into a shared rights module is followed, and the finding is bound to the entity. AccessContext.Append does not count, under-granting is legal, and kinds without access control are not judged.

yaml/placeholder-key-in-strings. A call with an argument fails the apply with an “unknown method” answer.

yaml/localization-ref-to-template. The apply answers that the localized string was not found, and the stand rolls back. A template key nobody references is left alone: code calls it legitimately.

code/url-params-partial-encoding. The “&” and “=” inside the value stay separators. Build the string with the parameters object and glue it to the base address. Off by default: whether a value can carry “&” is not statically visible.

code/url-data-scheme. The constructor puts a slash after the scheme and encodes “;” and “,” as path characters, the browser refuses the address with ERR_INVALID_URL, and the Image property takes no string. Serve the image from an HTTP service of the project or as a resource. A data address kept in a variable is not traced.

code/bound-property-assign. It looks like Height: =Common.IsNarrowScreen()?820:528. Inside a try/catch the refusal is invisible. A data binding, that is a bare path, is left alone: it is two-way by design.

yaml/event-needs-importance. The default is FromConstructor. One write that omits the value fails the apply on the constructor line. An explicit Importance: FromConstructor states the choice and silences the rule.

yaml/event-property-type. A project enumeration cannot go there. The list is read from the metamodel (EventLogEventProperty.Type), and ? and a Std:: qualification are tolerated. Variant values are written as string codes, with the allowed codes listed in the property’s Description.

code/collection-field-needs-req. TextPosition and ReadableArray<String> look like that. Scalar default values, unknown types and locally shadowed platform names are left alone.

code/var-needs-init. The compilation answers that the type has neither a constructor nor a default value. An enumeration, an annotation, a singleton and a name shadowed by a project type are skipped.

code/unknown-tabular-member. Judged are Object.Section.Member in an object form module, the bare section name and this.Section in the entity’s modules. The other platform’s habitual Count() is called Size() here. A module named after the section shadows it, and attributes are not judged.

code/global-unavailable. The apply answers that the method is unavailable in the current environment. Message is client-only and the dynamic evaluation is server-only. @OnClient and @OnServer override the module’s environment, and the availability comes from the per-member availability lines of the global context packages.

code/constant-unavailable. A constant exists in the environment its annotations name, or else in the environment of its module, and a method is compiled for the environments of its own annotations or of the module. The apply answers Variable "X" is not defined under the tag of the side the constant lacks. One probe project settled every combination in a form, a command and a common module of both environments: an @OnServer method, alone or with @AvailableFromClient or @Contextual, a method with both annotations and an unannotated method of a module of both environments were refused for a bare name, a name inside a lambda and a short interpolation %NAME, and the mirror case - a constant declared @OnServer, read by a client method - was refused too. The environment of the module comes from the yaml beside it, so the rule stays a file rule. A common module of the client alone is not judged: it refuses @OnServer by itself. The quick fix never takes a side away: an unannotated constant of a client module gets @OnServer @OnClient, an annotated one the missing annotation beside its own, and the probe project fixed that way compiled.

code/module-type-unavailable. A structure, an exception or an enumeration of a module exists where a constant would: in the environment its annotations name, or else in the environment of the module. A method compiled for the other side gets Type "X" is unavailable in the current environment wherever it names the type - a variable, a parameter and a result, a constructor, throw, a catch clause, a type check, a generic argument, a lambda - and Variable "X" is not defined for an enumeration read as a value, in the code or inside %{...}. Probe projects settled it in a form, a command and a common module of both environments, the mirror case included. The quick fix adds the missing annotation, and the fixed project compiled. It is withheld when a field of the type would not exist on the other side - a client-only type such as Component, a project type, a call in an initializer: the compiler refused a structure widened that way at the field.

code/qualified-member-unavailable. Another module reaches a constant, a structure or an enumeration of a common module by the qualified name. In a common module of both environments a declaration annotated for one side exists on that side only, and a method compiled for the other one is refused: Unknown property "Module.NAME" for a constant or an enumeration read as a value, Type "Module.Name" is unavailable in the current environment in a type position. A probe settled it for a server common module, an HTTP service, a form, a command, the declaring module itself and the interpolation %{Module.NAME}. A declaration without a visibility annotation fails outside its module on the visibility first, and the rule leaves it alone.

style/shadow-project-name. An example: a Warehouses variable next to the Warehouses catalog. Platform handler parameter names never collide with project names.

style/shadow-own-property. The platform IDE warns about such a variable. The properties are those of the method’s owner. For a component they are its declared properties and events, those of the platform type it inherits, and Components. In the object module of a catalog, a document or a processing element they are the attributes, tabular sections, reference, version stamp and deletion mark. For a record set it is the filter, for a scheduled job the parameters and properties of the job, for a structure its fields. Static methods, parameters, loop and catch variables are not judged, and a server method of a component sees only the properties marked Contextual.

style/redundant-union-member. String|String, String|Undefined|? and Array<String>|ReadableArray<String> look like that, a member under Object or under a base type of the catalog with the same arguments. The platform IDE warns about it, and a function type is not judged. The fix writes the union without those members. With freshly extracted generic metadata, a contract with a covariant parameter covers wider arguments, a read-only one and a mutable one alike (MutableArray<Object> covers Array<String>), and nested base formulas are substituted. The concrete Array, Map, Set and Collection keep their parameters invariant; missing metadata keeps the previous exact-argument behavior.

code/unclosed-resource. It looks like val Selection = Query{...}.Execute(). The platform closes a full pass by itself, and it logs an unclosed-resource event. Declaring the variable with use closes the resource on every exit path. A resource that arrived as a parameter, one the method closes by hand and one it returns to its caller are left to the author.

conventions/untranslated-visible-literal. The intent is counted per element kind, so a same-named property of another kind is not judged. On a project whose descriptor lists fewer than two localization languages the rule stays silent.

conventions/untranslated-code-literal. A sink is an argument of the platform message call, a property of an event-log event, or either of them one step away through a method that forwards its parameter. Markup, pure interpolation and single words are skipped. On a project whose descriptor lists fewer than two localization languages the rule stays silent.

conventions/missing-translation. One finding is reported, at the first occurrence in the file. The rule stays silent unless an xbsl-translation dictionary lives next to the project or above it (see xbsl translate).

code/unknown-structure-field. The type comes from the variable’s declaration (Module.Structure, a bare name for the declaring module), from a new constructor and from the element type of a for X in List loop. A name declared with anything else in the method, a namesake of a stdlib type, the second hop of a chain and Latin member spellings are not judged.

code/redundant-skip-undefined. For an iterable the fix uses ToArray(), preserving the array materialization. A sequence receives a warning without a fix.

code/redundant-cast. Found!.Reference as Goods.Reference over a query that reads the reference of that very catalog looks like that, and so does a union of references cast to the entity contract both of them implement. When the two types are the same, the fix removes the cast together with the parentheses around a single operand. A cast to a wider type is reported without a fix, since a declaration or an overload may need that type.

code/cast-to-non-null. Typically the operand is a nullable attribute a query reads, the result of Map.GetOrUndefined(...) or the result of a method declared T?. The fix puts ! in place of the cast. The operand is typed by its declarations, and a query column by the select list and the yaml of its table. A condition checked before the cast narrows nothing, and an operand the inference cannot name is not judged.

code/redundant-undefined-guard. The platform IDE warns about it. The type comes from a declaration, from a component of the paired markup such as Edit<Number>, or from the argument of a generic type, as in OnChangeEvent<String>.NewValue. The fix removes !, and removes ?? ... when the default does not widen the type.

code/redundant-type-check. Every type of the expression is one of the checked types or assignable to one: a base the catalog states (Array<String> fits ReadableArray<String>) and an entity contract a project element implements. The platform IDE warns about such a check. A column of a query row is typed by the SELECT list the way the cast rules read it: a field, a choice, arithmetic, a count. A field through a reference or of a left-joined table may be Null, and .ReplaceNull(...) takes the Null out.

comment/unknown-name. A case form of a known name, commented-out code and a chain naming another system are left alone. So is a name with another system named within two words of it: 1C:Enterprise, SSL, BTS or their Russian names, or a system the project declares with --other-system. The message says how to name the system when it is not there.

code/deprecated-api. ObjectStorage.UploadFromBytes(...) and ObjectStorage.Upload(Stream, Size) next to the current Upload("file", Bytes) look like that. The overloads are picked by the compatibility mode of the project, the arguments and their known types. A project description that declares no supported mode is read in the newest mode, as the platform reads it. The message names the replacement when the documentation does.

code/contract-method-not-abstract. An entity contract generates the contract type, the object type <Contract>.Object and a row type for each of its tabular sections, and each may have a module: <Contract>.xbsl, <Contract>.Object.xbsl and <Contract>.<Section>.xbsl. The probes compiled an ordinary method in each and got “Non-abstract method … cannot be defined”, and the same for a static method in all three and for a handler with a body in the object module; an abstract method without a body passes. A static method is advised to move out of the module. The module is joined to the yaml of its contract across the files of the run, a row module by the section the yaml declares. A yaml that does not parse leaves the modules of its contract alone.

Group details

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 (String|Number|?): the ? is not a type but the admissibility of Undefined, and Array<String|Number> 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 - the English IN, NOT, SELECT and their Russian equivalents.

Project properties (the project/ rules)

Four rules from the standard “Filling in the project properties”: Vendor and Name are identifiers built from the presentations, every word capitalized; Presentation and VendorPresentation are filled in - the official name of the project and of the company that developed it; Version 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 in its Attributes, Dimensions, Resources, TabularParts 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). For a Russian name this is morphology rather than a guess by the ending, so a singular noun the standard allows is told apart from a plural that reads as a genitive singular without the case. This needs the [morph] extra (pip install "xbsl[morph]"); without it Russian names stay silent. An English name in a translated tree is judged by its last word, with suffix heuristics and the irregular plurals listed, and needs no extra. Mass nouns and ambiguous tails are left undecided.

The rest: the letter yo and underscores in names, an abbreviation written in mixed case instead of all caps, an English term transliterated rather than kept as the original (Xml, not its Cyrillic spelling), an enumeration named with the word for type where the standard asks for the word for kind, the element kind repeated inside its own name, filler words such as the ones for management or manager, an environment suffix on a common module name (the environment is a property, not a name), a boolean attribute named by a negation instead of the positive form, an empty Presentation, and the prefixes required for certain kinds - access key, right and navigation. A catalog, a document and the other kinds whose top-level Presentation names an attribute are captioned in the interface section instead, and both captions are required: Interface.List.Presentation for the list and Interface.Object.Presentation for the object. An information register has no top-level Presentation and captions the list and the record (Interface.Record.Presentation), an accumulation register and a data journal the list alone. A constants set names a constant in its top-level Presentation and is captioned by the record, and by the list as well when it is periodic. A deprecated element starts its presentation and every caption with the mark of its project’s language: the Russian mark of the standard where the keys are Russian, (not used) where they are English, as in a translated tree. The mark of the other language does not count. An element is deprecated when its name starts with the prefix of the standard in either spelling (Deprecated in English) in front of the next word of the name, and a translated tree keeps that prefix in the English name whatever the dictionary entry says.

Code style conventions (the style/ rules)

Thirty-two rules that follow the platform documentation (“Code style conventions”, “Language idioms”) and the “Variable and constant names” development standard: layout and expression wrapping, naming, type descriptions and signatures, collection literals, string interpolation, and checks of boolean values and Undefined.

Of the variable-names standard the token-provable part is checked: abstract names, single-letter names outside lambdas, Cyrillic and Latin abbreviations not written as one word, boolean names built from the negation, a container type inside a name, numerals inside constant names, and the shadowing of project element names. Left to the author and review: redundant words in a name, abbreviations beyond the capitalization law, digits in place of a qualifier over a meaningful stem (Stage1 and Data1 differ only in meaning), and the abstractness of a constant name beyond numerals (the role of INITIAL_STAGE against the value of STAGE_QUESTIONNAIRE is invisible to tokens).

Five rules of the group go past tokens: they read the parsed module and repeat warnings of the platform IDE. style/constructor-literal reports a constructor that a literal of the type replaces, style/boolean-ternary a ternary with True and False branches, style/redundant-scope a scope that is the only statement of its block, and style/redundant-union-member a union member another one covers. style/shadow-own-property also reads the paired yaml and the platform type catalog, so a variable named like a property the component inherits, such as Title of a Group, is found as surely as one named like a declared property.

All thirty-two rules are on by default, at warning: clean code already satisfies them, and they guard against regressions. The flags that choose rules take the group as a whole:

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, while --enable switches on off-by-default rules on top of the defaults.

Query{ ... } blocks, which are a DSL of their own, and string literals with HTML, CSS or SVG for web views are excluded from these checks. Not covered, and left to the author and review: indentation being a multiple of four, collection idioms, Rows.Join() for bulk concatenation, the ?. and ?? idioms, and case instead of an else if chain.

Code semantics (the code/ rules)

The largest group: ninety-eight rules, sixty of them errors. These cover what the compiler rejects, and what the platform does differently from how the code reads. An unknown name or member. The arity of a call. The environment, meaning client code in a server method and the other way round. An instance reached through its type. A caught non-exception. An unclosed resource. A walk over a collection while it is being changed. And the platform traps whose only sign is the shape of the code. The group also repeats warnings of the platform IDE: an unused variable or import, a redundant cast, a guard against Undefined or an is check whose outcome the types already decide. Some of the rules are project-scoped, and --stdin does not run those: they need the paired yaml and the names of the objects.

Element descriptions (the yaml/ rules)

Sixty-four rules over the descriptions (.yaml): required and unique ids, known keys and types, references to components, handlers and localized strings, what the platform requires of field types (a reference and an enumeration admit an empty value), the settings of dynamic lists and forms, and the layout traps that apply without an error yet draw differently from the intent. Six rules are info and off, because they say “this is how the platform works” rather than “this is a mistake”.

Project conventions (the conventions/ rules)

Rules about what the project agreed on rather than what the platform demands. The base set carries the bilingual-project family. conventions/untranslated-visible-literal, on by default, reports visible text left as a Cyrillic literal where the project already routes the same property through the localization dictionary. conventions/untranslated-code-literal and conventions/missing-translation, both off, extend that to module literals and to the translation dictionary. Whether every human-readable string must come from the dictionary is a per-project decision, so the base set does not impose it.

The group is also the extension point by design. A project plugin registers its own house rules under conventions/ - a ban on task numbers in comments, internal references and the like - and decides their severity and defaults for that project; see Extending. What actually runs is what xbsl --list-rules prints; the table above lists the base set only.

The small groups

  • typography/ - typographic characters in prose and comments: em dash, the ellipsis character, curly quotes, guillemets in comments, a character that is not on the keyboard (an arrow, a comparison sign) and, for a project that writes a hyphen in its code comments, the en dash of a comment; plus the letter “ё” in the text a user reads. The group reads the resource files of the project too (.css, .js, .svg, .html);
  • comment/ - the wording of a comment: the subjunctive particle, the first person, a function word in capitals for emphasis and a condition written with a dash; comment/unknown-name checks the names a comment mentions against the project; comment/doc-marker and the comment/doc-tag-* rules judge the documentation comment of a declaration against what the environment shows. The group reads the comments of modules, element descriptions and resource files (the name rule reads modules and element descriptions), and the first person and the capitals of emphasis are read in the English lines of the translation dictionary too; the group is off by default, except the comment/doc-tag-* rules; a project that keeps its comments impersonal turns it on with --enable comment;
  • translation/ - the English of the translation dictionary: translation/english-shape reads the values of the xbsl-translation files, whose text xbsl translate --strict never judges;
  • whitespace/ - trailing spaces and mixed newlines;
  • encoding/ - a file that is not UTF-8;
  • structure/ - the pairing of Name.yaml and Name.xbsl;
  • security/ - a secret in the sources (a token, a password, a key);
  • form/ - a form handler the module does not have, and a handler whose signature contradicts the event of the component (project-scoped rules);
  • query/ - queries: an unknown table, ISNULL, a named parameter, an immediate deletion mark and the standard about IN with a subquery (discussed above).

Enabling and disabling

--select and --ignore accept a rule identifier, a group (the part before /, e.g. style) or a tier letter A/B/C/D. A plugin may override a rule’s severity (the xbsl.severity entry-points group); XBSL_NO_PLUGINS=1 disables plugins and restores the built-in values from this table.

code/procedure-as-value.

Checks local and cross-module project calls in value expressions. Unknown targets, ambiguous overloads and standalone procedure calls are left alone. No automatic fix is offered.

code/contract-parameter-name.

Compares parameter names only for an unambiguous project service contract and matching signatures. Reports an error in compatibility mode 8.0 or later, a warning in earlier modes. A project description that declares no supported mode (none at all, a value that names no mode, a mode below the oldest one) is read in the newest mode, as the platform reads it; a run without the project description is not judged. No automatic fix is offered.

conventions/platform-translation-shadow.

Runs only in projects with a translation dictionary. Reports a Cyrillic declaration collected by the translator when it suppresses a known platform mapping and has no applicable explicit token pair. Local variables and parameters are excluded. Add a dictionary pair; renaming is optional and is never applied automatically. ASCII declarations are excluded by the translator’s contract, so a fully translated English tree has no findings from this rule.

code/client-pattern-unicode-class. Disabled by default. Enable with --select code/client-pattern-unicode-class or rule configuration only after confirming that your target client rejects Unicode class \p. The language dataset version does not identify client-engine capabilities. Only the literal first argument of new Pattern(...) in a proven client module is checked, including the client execution of a shared common module. Methods annotated @OnServer, dynamic or interpolated patterns, strings used for another purpose, and escaped literal text are skipped. \P and other classes are not checked. There is no automatic fix: replacing a Unicode class with ASCII changes the accepted character set. Test the chosen replacement in your own client; successful server compilation does not prove client execution.

Last updated on October 7, 2026

Was this page helpful?