@metadev/quid-core
v0.0.1
Published
Quid: a style-free abstract UI language/DSL. Grammar, parser, AST, validator and catalog model.
Readme
@metadev/quid-core
Quid is a small, style-free language/DSL for describing user interfaces: views, components, controls, properties, events and a few statements. The core in this repository is framework-free TypeScript: the grammar, the parser, the AST, the validator, the catalog model and a serialiser. It has no runtime dependencies.
A catalog lists what a description may use: control types with their properties and events, enums, typed classes and the data services it may call. The validator rejects anything outside the catalog, which is what makes Quid a safe target for generated UIs (for example, from an LLM that only gets to choose and configure trusted pieces).
See demo on https://quid.metadev.pro.
Status: 0.x, not published yet. The API may change before 1.0.
Install
npm install @metadev/quid-coreRequires Node.js 22 or later. The package ships ESM and CommonJS builds with types.
Use
import { AstBuilder, UIValidator, toEssential, StringBuilder } from '@metadev/quid-core';
import { getCatalog } from './my-catalog'; // a UICatalog: controls, enums, services, classes
const source = `view v1
label l1
text = "Hello"
`;
const ast = AstBuilder.parse(source, 'hello.quid'); // throws UaiSyntaxError on invalid syntax
const validator = new UIValidator();
validator.loadCatalog(getCatalog());
const { errors } = validator.validate(ast); // located errors with codes, see below
const out = new StringBuilder();
toEssential(ast, out); // serialise the AST
console.log(out.toString());The catalogs in examples/catalogs show the shape: neutral.ts is a minimal one, base-catalog.ts a larger, form-oriented palette.
The language
Indentation nests, one construct per line:
component A1
property n: string
event click(a: number)
button t1
title = "A"
click() => onClick()- Controls and components:
view,component, and any control type declared in the catalog, optionally named (button t1). - Properties:
title = "A"; values can be literals, identifiers, expressions and bindings ({{a.b}}). - Declarations:
property n: stringandevent click(a: number)on a component. - Handlers:
click() => onClick(). - Functions and statements:
fun, assignment,if/else,for,foreach,while,loop/until,emit, calls and indexing. - Data services:
services.<name>(args)is checked against the services of the catalog.
More examples are in examples/samples and in the specs next to the sources.
Validation errors
Each error has a code, a message and a source location. The codes are grouped:
| Range | About |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| E1xx | Structure: duplicate names (E100) and properties (E101), unknown control (E102) or property (E103), missing required property (E104), invalid property value (E105) or enum value (E106) |
| E2xx | Expressions, types and services: unknown service (E207), wrong number of arguments (E209) |
| E3xx | Events: undefined event (E301), wrong number (E302) or type (E303) of parameters in emit |
Develop
npm ci
npm test # generates the parser, runs the tests
npm run typecheck
npm run lint
npm run build # ESM + CJS + types in dist/The parser is generated from grammar/uai.pegjs with Peggy and ts-pegjs into src/uai/parser.generated.ts (not committed). The golden-master tests in test/golden pin the parser and serialiser output; see docs/dialect-merge.md for how they were built.
Contributing
See CONTRIBUTING.md. Contributions require a DCO sign-off. This project follows a Code of Conduct; to report a security problem, see SECURITY.md.
Licence
Apache-2.0. Copyright Metadev.
