oh-dsl
v0.3.0
Published
QVoG DSL interface
Readme
qvog-dsl
DSL interface for QVoG.
Project Map
Below is the relation of all modules for a DSL-enabled linter. This repository is the DSL interface, which mainly provide the DSL grammar.
+-----------------------------------------+
| DSL Rule (User Written) |
+----------+---------------------+--------+
| |
v v
+-------------------+ +-----------------+
| DSL Interface | | *Additional |
| (This Repo) |<--+ Type Definition |
+-------------------+ | (Optional) |
^ +-----------------+
| ^
+----------+--------+ |
| +--------+------+ | |
| | DSL Adapter | +------------+
| +---------------+ |
| | | +-----------------+
| v | | |
| +--------+------+ | | **Console |
| | Native Engine | |<--+ Application |
| +---------------+ | | |
+-------------------+ +-----------------+A demo implementation of all modules (without * and **) can be found under test/mock/.
About This Repository
Setup & Scripts
It is a standard npm library, run npm install to install the dependencies.
npm run build # build the project
npm run docs # build the documentation
npm run lint # lint the project
npm run format # format the project using prettier
npm run test # run unit tests
npm run coverage # run unit tests with coverageProject Structure
Source files are under src/ directory. src/type/ provides type wrapper around those in ohos-typescript. src/dsl/ defines the grammar of the DSL, and interfaces for the DSL adapter.
Currently, only a small subset of types is wrapped, more wrappers should be added in the future.
Tests are placed under test/ directory, and a mock linter engine is implemented as a demonstration under test/mock/, including the mock DSL adapter. Example DSL rules are placed under test/mock/rules/.
How To...
Implement A Linter?
Refer to
test/mock/MockEngine.tsfor example.
To implement a linter, it is recommended to separate the core engine from the final console application. In this way, the rules defined via DSL can be translated first, so that the engine only need to know its native rules.
The core engine can be implemented freely, but it should meet the minimum requirements defined by EngineCapability interface, and provide a global method to get such an object.
Implement A DSL Adapter?
Refer to
test/mock/MockAdapter.tsfor example.
The DSL is defined in Fluent-API style, so to translate it into engine-specific rules, you need to implement the interface. To be more specific, AwaitMatch, AwaitThen and AwaitReport. Then, implement the rule function as the entry of each rule. Just ensure the final value returned by report is DslRule<T>, where T is the type of native rule.
Then, you should define functions to load DSL rule from module or external file. These are utility functions, thereby no specific requirements for them.
Write Rules in DSL?
Refer to
test/mock/rules/Example.tsfor example.
A DSL rule is represented by a value of type DslRule<T>, so writing a rule is equivalent to creating such a value.
The basic layout of a DSL is given below. Write one rule each file and export it as default.
export default rule(/* ... */)
.match(/* ... */)
.when(/* ... */)
.report(/* ... */);The rule will be applied to every AST node parsed from the source file. For each node, match defines the preliminary check action to decide whether this node is of interest or not. For each matched node, then defines the detailed check on it. If the node matches both checks, it will be reported by the action defined in report.
For built-in DSL rules, you can simply import and use them. For external DSL or those under development, you can use the functions provided by DSL adapter to load them.
