hana-linter
A command line that checks the names of the native SAP HANA artifact files in a CAP project, and the identifiers inside them, against regex rules the project keeps in a config file.
Lints the .hdb* files under a CAP project's rootDir against naming rules the project keeps in .hana-linter.json: regex patterns grouped per file extension, as groups.all where every rule must match or groups.any where one is enough, plus an optional folderName that fixes which folder matching files sit in. Content rules reach inside the files for identifiers a parser extracts, such as the columns of a .hdbtable or the input parameters of a .hdbprocedure, read out by Chevrotain lexers for the SQL DDL formats and by fast-xml-parser for the XML of .hdbcalculationview. It either scans rootDir recursively or validates only the file paths it is given, which is the mode the README wires to lint-staged and a husky pre-commit hook, and it exits 1 when it finds violations. Naming is the whole of it: every rule is a regex over a name, and the README marks the project as work in progress, with configuration options and supported artifact types able to change between releases.
Facts
Where it sits
Who is behind it
In the atlas: maintains 6, contributes to 3@qualituremaintainer
Before choosing this
Conditions
PracticalFunctional boundary
Everything it checks is a name: a file name under rootDir, or an identifier a parser extracted from a file, so a convention that cannot be written as a regex over one name has no rule shape here. Content rules targeting .hdbanalyticalprivilege or .hdbconstraint return no results, which the README states as not yet implemented, so conventions centred on those two artifact types go unchecked.
What it declares
Every artifact
- Type
- CLI
- Origin
- Independently maintained
- Runtime
- build time
As a CLI
- Distributed through
- does not say
Connections
Catching problems in code, models and configuration by rules
Download
Install
npm add hana-linterDerived from the package name. No recipe recorded; the README has the configuration.
README
quoted from qualiture/hana-linter under MIT, readhana-linter
Naming-convention lint for SAP HANA artifacts in CAP projects.
⚠️ Work in progress. This project is under active development. APIs, configuration options, and supported artifact types may change between releases. See Parser Status for the current state of content extraction support.
Lint SAP HANA artifact file names and content identifiers in CAP projects using configurable regex-based naming rules.
Why
Teams often rely on naming conventions for HANA artifacts such as tables and views. When these conventions are enforced manually, drift is common and code reviews become noisy.
hana-linter helps you:
- enforce naming standards consistently
- catch violations early in local development and CI
- apply different rules per file extension
- keep naming policy in version control via a single config file
How It Works
hana-linter reads a .hana-linter.json file and validates artifact file names against rules grouped by extension.
It supports two lint modes:
- Full scan mode: no file arguments, recursively scans
rootDir - File-list mode: pass file paths, only those files are validated
Rule groups per extension:
groups.all: every rule must match (AND)groups.any: at least one rule must match (OR)
You can define extension: "*" as a shared rule set. Its rules are applied to every file extension and are merged with any extension-specific rule set.
Content-based linting uses purpose-built parsers to reliably extract identifiers from HANA artifact files. SQL DDL artifact types (.hdbtable, .hdbview, .hdbprocedure, .hdbfunction, .hdbtabletype, .hdbrole, .hdbsequence, .hdbindex, .hdbtrigger) use Chevrotain-powered lexers and CST parsers that correctly handle block and line comments, multi-line definitions, quoted identifiers, and HANA-specific DDL constructs. The JSON-like .hdbschedulerjob format is also parsed with Chevrotain, tolerating C-style comments (// and /* … */) and trailing commas that standard JSON.parse() rejects. The XML-based .hdbcalculationview format uses fast-xml-parser to navigate the logical model tree — without the false positives and false negatives that ad-hoc regex scanning produces.
Parser Status
Work in progress. Not all artifact types have been migrated to the Chevrotain-based parsing infrastructure yet.
| Artifact extension | Content extractor | Status |
|---|---|---|
.hdbtable | Chevrotain lexer + CST | ✅ Migrated |
.hdbview | Chevrotain lexer + CST | ✅ Migrated |
.hdbprocedure | Chevrotain lexer + CST | ✅ Migrated |
.hdbfunction | Chevrotain lexer + CST | ✅ Migrated |
.hdbtabletype | Chevrotain lexer + CST | ✅ Migrated |
.hdbrole | Chevrotain lexer + CST | ✅ Migrated |
.hdbcalculationview | fast-xml-parser (XML) | ✅ Migrated |
.hdbanalyticalprivilege | — | ❌ Not yet implemented |
.hdbsequence | Chevrotain lexer + CST | ✅ Migrated |
.hdbconstraint | — | ❌ Not yet implemented |
.hdbschedulerjob | Chevrotain lexer + CST | ✅ Migrated |
.hdbindex | Chevrotain lexer + CST | ✅ Migrated |
.hdbtrigger | Chevrotain lexer + CST | ✅ Migrated |
- The regex file name validations for all of the above listed extensions are implemented.
- Not implemented:
contentRuleSetstargeting.hdbanalyticalprivilegeor.hdbconstraintwill silently return no results — no identifiers are extracted and no content issues are raised.
Install
Local (recommended for projects)
npm install --save-dev hana-linter
Run with:
npx hana-linter
Global
npm install -g hana-linter
Quick Start
- Generate a default config in your project root:
hana-linter init
- Run the linter:
hana-linter
- If needed, regenerate and overwrite config:
hana-linter init --force
Commands
hana-linter
Run lint using .hana-linter.json from the current working directory.
hana-linter
Lint specific files only:
hana-linter db/src/T_CUSTOMER.hdbtable db/src/V_ACTIVE_USERS.hdbview
Use a custom config path:
hana-linter --config ./config/.hana-linter.json
hana-linter init
Create .hana-linter.json in the current working directory from the bundled default template.
hana-linter init
Overwrite existing config:
hana-linter init --force
Configuration
Create a .hana-linter.json file in your project root.
Configuration Fields
rootDir(string): directory to scan in full scan modeignoredDirectories(string[]): folder names ignored during recursive traversalextensionRuleSets(array): rule definitions grouped by file extensioncontentRuleSets(optional array): naming rules for identifiers extracted from file contents (for example table fields and procedure/function parameters)
Each extensionRuleSets item contains:
extension(string): target extension, for example.hdbtable; use*to target all extensionsfolderName(optional string): enforce that matching files are located in a folder with this name (at any depth underrootDir)groups.all(optional array): all rules must matchgroups.any(optional array): at least one rule must match
Each rule contains:
description(string): readable rule label for outputpattern(string): regex source (without/delimiters)flags(optional string): regex flags, for examplei,u,iu
At least one of groups.all or groups.any must be present for each extension.
When folderName is omitted, no folder-location enforcement is applied.
Each contentRuleSets item contains:
extension(string): target extension, for example.hdbtable; use*to target all extensionstarget(string): extracted identifier type to validate; one offield,inputParameter,outputParameter,roleName,grantedRoleName,sequenceName,jobAction,indexName,triggerNamegroups.all(optional array): all rules must matchgroups.any(optional array): at least one rule must match
Supported extractors in this version:
target | Supported extensions | Extracted identifiers |
|---|---|---|
field | .hdbtable | Column names |
field | .hdbview | Column aliases (explicit list or AS aliases) |
field | .hdbtabletype | Column names |
inputParameter | .hdbprocedure | IN and INOUT parameters |
inputParameter | .hdbfunction | IN parameters (functions accept IN only) |
outputParameter | .hdbprocedure | OUT and INOUT parameters |
roleName | .hdbrole | The role name defined in the file |
grantedRoleName | .hdbrole | Each role listed in extends roles { ... } |
field | .hdbcalculationview | Output attributes, calculated attributes, base/calculated/restricted measures |
inputParameter | .hdbcalculationview | Input parameters (variable[@parameter="true"]) |
sequenceName | .hdbsequence | The sequence name declared in the file |
jobAction | .hdbschedulerjob | The procedure/function reference in the action field |
indexName | .hdbindex | The index name declared in the file |
triggerName | .hdbtrigger | The trigger name declared in the file |
Default Config Example
{
"rootDir": "db",
"ignoredDirectories": ["node_modules", ".git", "gen"],
"extensionRuleSets": [
{
"extension": "*",
"groups": {
"all": [
{
"description": "Upper snake case only",
"pattern": "^[A-Z0-9]+(?:_[A-Z0-9]+)*$"
},
{
"description": "Max length 30",
"pattern": "^.{1,30}$",
"flags": "u"
}
]
}
},
{
"extension": ".hdbtable",
"folderName": "tables",
"groups": {
"any": [
{
"description": "Prefix T_",
"pattern": "^T_.+"
},
{
"description": "Prefix TX_",
"pattern": "^TX_.+"
}
]
}
},
{
"extension": ".hdbview",
"groups": {
"all": [
{
"description": "Starts with V_",
"pattern": "^V_.+"
}
]
}
}
],
"contentRuleSets": [
{
"extension": ".hdbtable",
"target": "field",
"groups": {
"all": [
{
"description": "Field names in uppercase snake case",
"pattern": "^[A-Z0-9]+(?:_[A-Z0-9]+)*$"
}
]
}
},
{
"extension": ".hdbprocedure",
"target": "inputParameter",
"groups": {
"all": [
{
"description": "Input parameters prefixed with IP_",
"pattern": "^IP_[A-Z0-9_]+$"
}
]
}
},
{
"extension": ".hdbprocedure",
"target": "outputParameter",
"groups": {
"all": [
{
"description": "Output parameters prefixed with OP_",
"pattern": "^OP_[A-Z0-9_]+$"
}
]
}
},
{
"extension": ".hdbview",
"target": "field",
"groups": {
"all": [
{
"description": "View column aliases in uppercase snake case",
"pattern": "^[A-Z0-9]+(?:_[A-Z0-9]+)*$"
}
]
}
},
{
"extension": ".hdbfunction",
"target": "inputParameter",
"groups": {
"all": [
{
"description": "Input parameters prefixed with IP_",
"pattern": "^IP_[A-Z0-9_]+$"
}
]
}
},
{
"extension": ".hdbtabletype",
"target": "field",
"groups": {
"all": [
{
"description": "Field names in uppercase snake case",
"pattern": "^[A-Z0-9]+(?:_[A-Z0-9]+)*$"
}
]
}
},
{
"extension": ".hdbrole",
"target": "roleName",
"groups": {
"all": [
{
"description": "Role names prefixed with R_",
"pattern": "^R_.+"
}
]
}
},
{
"extension": ".hdbcalculationview",
"target": "field",
"groups": {
"all": [
{
"description": "Output column IDs in uppercase snake case",
"pattern": "^[A-Z0-9]+(?:_[A-Z0-9]+)*$"
}
]
}
},
{
"extension": ".hdbcalculationview",
"target": "inputParameter",
"groups": {
"all": [
{
"description": "Input parameters prefixed with IP_",
"pattern": "^IP_[A-Z0-9_]+$"
}
]
}
},
{
"extension": ".hdbsequence",
"target": "sequenceName",
"groups": {
"all": [
{
"description": "Sequence names in uppercase snake case",
"pattern": "^[A-Z0-9]+(?:_[A-Z0-9]+)*$"
}
]
}
},
{
"extension": ".hdbschedulerjob",
"target": "jobAction",
"groups": {
"all": [
{
"description": "Job action must reference a package-qualified procedure (contains ::)",
"pattern": "::"
}
]
}
},
{
"extension": ".hdbindex",
"target": "indexName",
"groups": {
"all": [
{
"description": "Index names in uppercase snake case",
"pattern": "^[A-Z0-9]+(?:_[A-Z0-9]+)*$"
}
]
}
},
{
"extension": ".hdbtrigger",
"target": "triggerName",
"groups": {
"all": [
{
"description": "Trigger names in uppercase snake case",
"pattern": "^[A-Z0-9]+(?:_[A-Z0-9]+)*$"
}
]
}
}
]
}
Exit Codes
0: lint passed orinitcompleted successfully1: lint violations found or command failed
This makes the CLI suitable for CI pipelines.
CI Example
name: lint-hana-names
on: [push, pull_request]
jobs:
hana-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx hana-linter
Pre-commit Hook (husky + lint-staged)
hana-linter's file-list mode (passing files as arguments) integrates cleanly with lint-staged: lint-staged appends each staged file that matches the glob to the command, so only the files you are about to commit are linted.
1. Install the tools
npm install --save-dev husky lint-staged
npx husky init
2. Configure lint-staged
Add a lint-staged key to package.json:
{
"lint-staged": {
"*.hdb*": "hana-linter"
}
}
lint-staged turns this into hana-linter <file1> <file2> … for every staged file that matches the glob, which is exactly the file-list mode hana-linter supports.
3. Wire the pre-commit hook
Replace the contents of .husky/pre-commit with:
npx lint-staged
Now, every git commit will automatically run hana-linter against the staged HANA artifact files. If any naming violations are found, the commit is blocked and the issues are reported in the terminal.
Tip: Add
hana-lintertodependencies(notdevDependencies) if the linter also runs in production CI, so it is available after a plainnpm ci --productioninstall. For pre-commit-only use,devDependenciesis fine.
Requirements
- Node.js >= 14
- npm >= 7
Contributing
Contributions are welcome. Please open an issue or submit a pull request.
License
MIT
History
Others providing
Compare all 11 on the Linting page →- @cbs-consulting/cds-eslint@cbs-consulting/cds-eslintAn ESLint plugin for CDS files carrying one consultancy's own rules, published so that the consultancy's projects lint their CDS models the same way.independent, capESLint plugin with one consultancy's rules for CDS filesfrom CAP
- @cbs-consulting/tools@cbs-consulting/toolsShared ESLint configuration for SAPUI5 and CAP projects, the config rather than the rules, so a team adopts a house style by adding one dependency.independent, capShared ESLint configuration for SAPUI5 and CAP projectsfrom CAP
- ui5plugin-linterui5plugin-linterA command-line linter for UI5 projects, run as ui5linter, that checks JavaScript and TypeScript classes, XML views and fragments, and i18n properties files.independent, ui5Command-line linter for UI5 classes, XML views and i18n filesfrom UI5
- ui5pluginui5pluginThe SAPUI5 Extension for Visual Studio Code: completion, definitions, CodeLens, diagnostics, code actions, hover and an XML formatter for UI5 views, controllers and manifest.json.independent, ui5SAPUI5 extension for Visual Studio Codefrom UI5
- eslint-plugin-better-cap-configeslint-plugin-better-cap-configA set of ESLint rules that read CAP configuration and flag the cds settings that have since been deprecated, putting that check in the linter a project already runs, with no dependencies of its own.independent, capESLint rules flagging deprecated CAP configurationfrom CAP
- @sap/eslint-plugin-cds@sap/eslint-plugin-cdsSAP's ESLint plugin for CDS, carrying the model and environment rules capire calls best practice and universal for every CAP project.sap official, capSAP's ESLint plugin for CDSfrom CAP
- @sap-ux/eslint-plugin-fiori-tools@sap-ux/eslint-plugin-fiori-toolsESLint rules from the Fiori tools team, aimed at the parts of a project their generators produce.sap official, capESLint rules for projects the Fiori tools generators producefrom CAP
- vscode-ui5-language-assistantvscode-ui5-language-assistantSAP's VS Code extension for SAPUI5 and OpenUI5: completion, validation, hover tooltips, go to definition, quick fix and formatting for XML views, and completion and validation for manifest.json.sap official, ui5VS Code extension for SAPUI5 and OpenUI5 XML views and manifestfrom UI5
- @satiroglu/kaev@satiroglu/kaevA command line that runs rule-based checks over a SAPUI5 or OpenUI5 project, reporting each finding with a rule id, a category, a severity, a confidence and the file it sits in.independent, ui5Rule-based checker for SAPUI5 and OpenUI5 projectsfrom UI5
- @ui5/linter@ui5/linterSAP's static analysis tool for UI5 projects: it scans JavaScript, TypeScript, XML, JSON and other files for deprecated APIs, global variables and possible CSP violations, and fixes part of them with --fix.sap official, ui5Static analysis tool for UI5 projectsfrom UI5
Details
Sources
Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.
Compatibility and provenance
History in the atlas
- First seen.
For your agent
- Ref
artifact:qualiture-hana-linter- JSON
- /artifacts/qualiture-hana-linter.json
- MCP
- Connecting an agent