Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
f5eef85
make LanguageKeys type-safe
JohannesMeierSE Aug 14, 2025
ea6f410
exploit Specifics['LanguageKeys'] to simplify inference rules for fun…
JohannesMeierSE Aug 15, 2025
8e305f0
improved the changelog, wrote documentation
JohannesMeierSE Sep 1, 2025
65d6bf8
refactorings: moved existing definitions into another file, used exis…
JohannesMeierSE Sep 1, 2025
7a9db69
some renamings to make names more clear
JohannesMeierSE Sep 1, 2025
6587704
refactoring: moved definitions into another file
JohannesMeierSE Sep 1, 2025
7ca4027
renamed internal <TypeType> generics
JohannesMeierSE Sep 1, 2025
66edf95
investigated a strange TSC issue
JohannesMeierSE Sep 1, 2025
4c10c76
`languageProperty` supports only valid property names of the given `l…
JohannesMeierSE Sep 4, 2025
82148ac
fixes according to the review
JohannesMeierSE Feb 11, 2026
a5e7ea1
calculate union of language types for multiple language keys (as deve…
JohannesMeierSE Feb 11, 2026
4cf9897
made registration options more explicit (result of joint discussion w…
JohannesMeierSE Feb 11, 2026
f915b86
make the properties of language nodes, which shall be hidden, customi…
JohannesMeierSE Feb 13, 2026
2fc4542
fixed watch script
JohannesMeierSE Feb 13, 2026
051bb92
documented the case, if there is no list of concrete language keys
JohannesMeierSE Feb 13, 2026
bea149b
Provide `addValidationRulesForLanguageNodes` in core Typir
JohannesMeierSE Feb 13, 2026
f0a419e
Provide `addInferenceRulesForLanguageNodes` in core Typir
JohannesMeierSE Feb 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,34 @@ Note that the versions "0.x.0" probably will include breaking changes.
For each minor and major version, there is a corresponding [milestone on GitHub](https://github.com/TypeFox/typir/milestones).



## v0.4.0 (2025-??-??)

[Linked issues and PRs for v0.4.0](https://github.com/TypeFox/typir/milestone/5)

### New features

- Introduced `TypirSpecifics['LanguageKeys']` (in `typir.ts`) to make the available language nodes with their keys and TypeScript types explicit (#93):
- By default, Typir predefines neither language nodes nor language keys in advance, i.e. any `string` values are usable as language key.
- By default, Typir-Langium supports exactly the language nodes and language types, which are derived from the grammar and generated by Langium into the `ast.ts`. Looking into the LOX example, `LoxAstType` inside `examples/lox/src/language/generated/ast.ts` lists all language keys (on the left of colon) and maps them to the (TypeScript interfaces/types of the) language nodes (on the right of the colon).
- When restricting the possible language keys, the TypeScript compiler shows errors, if invalid language keys are used. This happens, among others, inside inference rules or for registering validation rules. This improves type safety on TypeScript level for developers applying Typir.
- If language keys are restricted, inside an inference rule with a value for `languageKey` and without a value for `filter`, it is possible now to skip the expected TypeScript type for the input node of the `matching` property, as demonstrated in the updated examples for (L)OX. This improves the usability and type-safety of the API.
- When reporting validation issues, `languageProperty` accepts only valid property names of the given `languageNode` (#93).
- Introduced `TypirSpecifics['OmittedLanguageNodeProperties']` to omit some of the existing properties of language nodes.
- Introduced `typir.validation.Collector.addValidationRulesForLanguageNodes()` to register multiple validation rules for language keys at once with improved TypeScript safety (#93).
- Introduced `typir.Inference.addInferenceRulesForLanguageNodes()` to register multiple inference rules for language keys at once with improved TypeScript safety (#93).

### Breaking changes

- Renamed `TypirLangiumSpecifics['AstTypes']` to `TypirLangiumSpecifics['LanguageKeys']` to align it with the new `TypirSpecifics['LanguageKeys']`, as described above (#93).
- Renamed `typir.validation.Collector.addValidationRulesForAstNodes` to `addValidationRulesForLanguageNodes` to align it with the new API in Typir (core), as described above (#93).
- Renamed `typir.Inference.addInferenceRulesForAstNodes` to `addInferenceRulesForLanguageNodes` to align it with the new API in Typir (core), as described above (#93).

### Fixed bugs

-



## v0.3.3 (2026-02-10)

Expand All @@ -23,13 +41,15 @@ For each minor and major version, there is a corresponding [milestone on GitHub]
- Updated Typir-Langium to Langium v4.2.0 (#103).



## v0.3.2 (2026-01-13)

### Fixed bugs

- Use browser-safe `isSet` and `isMap` implementation to fix #96 (#98, #97).



## v0.3.1 (2025-11-27)

### New features
Expand All @@ -43,6 +63,7 @@ For each minor and major version, there is a corresponding [milestone on GitHub]
- When checking the equality of custom types, the values for the same property might have different TypeScript types, since optional properties might be set to `undefined` (#94).



## v0.3.0 (2025-08-15)

[Linked issues and PRs for v0.3.0](https://github.com/TypeFox/typir/milestone/4)
Expand Down Expand Up @@ -74,7 +95,6 @@ For each minor and major version, there is a corresponding [milestone on GitHub]
LanguageType: unknown;
}
```

- `TypirLangiumSpecifics` extends the Typir specifics for Langium, concretizes the language type and enables to register the available AST types of the current Langium grammar as `AstTypes`:

```typescript
Expand Down Expand Up @@ -106,18 +126,21 @@ For each minor and major version, there is a corresponding [milestone on GitHub]
- Fixed the implementation for merging modules for dependency injection (DI), it is exactly the same fix from [Langium](https://github.com/eclipse-langium/langium/pull/1939), since we reused its DI implementation (#79).



## v0.2.2 (2025-08-01)

- Fixed wrong imports of `assertUnreachable` (#86)
- Copy instead of reuse arrays with language keys to prevent side effects (#87)
- Updated Typir-Langium to Langium v3.5 (#88)



## v0.2.1 (2025-04-09)

- Export `test-utils.ts` which are using `vitest` via the new namespace `'typir/test'` in order to not pollute production code with vitest dependencies (#68)



## v0.2.0 (2025-03-31)

[Linked issues and PRs for v0.2.0](https://github.com/TypeFox/typir/milestone/3)
Expand Down Expand Up @@ -174,19 +197,22 @@ For each minor and major version, there is a corresponding [milestone on GitHub]
- The inference logic in case of zero arguments (e.g. for function calls or class literals) was not accurate enough (#64).



## v0.1.2 (2024-12-20)

- Replaced absolute paths in READMEs by relative paths, which is a requirement for correct links on NPM
- Edit: Note that the tag for this release was accidentally added on the branch `jm/v0.1.2`, not on the `main` branch.



## v0.1.1 (2024-12-20)

- Improved the READMEs in the packages `typir` and `typir-langium`.
- Improved the CONTRIBUTING.md.
- Improved source code for Tiny Typir in `api-example.test.ts`.



## v0.1.0 (2024-12-20)

This is the first official release of Typir.
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ The roadmap includes, among other, these features:

- More predefined types: structurally typed classes, lambdas, generics, constrained primitive types (e.g. numbers with upper and lower bound), ...
- Calculate types, e.g. operators whose return types depend on their current input types
- Simplified API for custom types

For the released versions of Typir, see the [CHANGELOG.md](./CHANGELOG.md).

Expand Down
6 changes: 6 additions & 0 deletions documentation/bindings/binding-langium.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ Typir-Langium is a dedicated binding of Typir for languages and DSLs which are d
the language workbench for developing textual domain-specific languages (DSLs) in the web.

TODO

## Validation

All properties of usual diagnostics in Langium (as defined in `DiagnosticInfo`) are supported, when creating validation issues in Typir-Langiums.
This enables, among other use cases, to register code actions for type-related validation issues (see `lox-code-actions.ts` for an example).
Note that `node`, `property` and `index` are renamed to `languageNode`, `languageProperty` and `languageIndex` to be in sync with Typir core.
3 changes: 2 additions & 1 deletion documentation/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ As described in the [design section](./design.md), nearly all features of Typir
for which Typir provides classes implementing these interfaces as default implementations. These interfaces and implementations are composed in ...

- `typir.ts` for Typir (core)
- `typir-langium.ts` for Typir-Langium
- `typir-langium.ts` for Typir-Langium, reusing and adjusting the Typir core services

Some examples how to customize existing services and how to add new services are sketched in `customization-example.test.ts`.

Expand All @@ -28,6 +28,7 @@ const customizedTypir = createTypirServices({
});
```


## Add additional services

Additional services need to be explicitly specified.
Expand Down
97 changes: 79 additions & 18 deletions documentation/design.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# Design

This describes the main design principles of Typir.
This describes the main design principles of and the terminology used by Typir.

## Core principles

### Type
## Type

Each type exists only once in a Typir instance. Types at runtime are instances of a sub-class of the TypeScript class `Type`.
Two different instances of `Type` represent two different types in Typir.

All types need to have *unique identifiers* in order to identifier duplicate types and to access types by their identifier.
If Typir reports errors regarding non-unique identifiers, check the following possibles reasons for colliding identifiers:
Expand All @@ -14,37 +16,96 @@ If Typir reports errors regarding non-unique identifiers, check the following po

Types also have a *name*, which is used as a short name for types, e.g. used to be shown in error messages to users. Names don't need to be unique.

TODO:
TODO: states/lifecycle of a type

Each type has exactly one kind, as explained below.


- single instances
- kind
## Kind / Factory

### Kind

### Type graph
## Type graph

Each type system, i.e. each instance of the `TypirServices`, has one type graph:
Each type system, i.e. each instance of the `TypirServices`, has one type graph, which stores the available types and their relationships:

- nodes are types, e.g. primitive types and function types
- edges are relationships between types, e.g. edges representing implicit conversion between two types

### Incrementality (under construction)

## Incrementality (under construction)

- add/remove types
- add/remove rules and relationships

### Services and default implementations

## Language

Usually, type systems are created to do some type checking on textual languages, including domain-specific languages (DSLs) and general-purpose programming languages. Programs respective text conforming to these languages are parsed and provided as abstract syntax trees (ASTs) in-memory.
ASTs usually consist of a tree of nodes (realized as JavaScript objects at runtime), which represent a small part of the program/text after parsing.
During linking, cross-references between the nodes of the tree are established, i.e. the tree becomes a graph.
Type checking is done on these ASTs.

### Language node

Since Typir has no preconditions regarding the structure of the AST or the technical details of the AST nodes in order to provide type checking for any data structure,
the term *language node* is used to describe a single node in the AST or a single element in a complex data structure.
As an example, in the context of Langium each `AstNode` is a language node in Typir.

While the definition of types and their relationships is independent from the AST,
type inference and validations are done on language nodes,
e.g. an inference rule gets a language node as input and returns its inferred Typir type.
All information Typir needs to know about language nodes is specified in the APIs, including the APIs for inference rules, validations rules and the [language service](./services/language.md).

### Language type

The TypeScript type of a language node is called *language type*.
If the TypeScript types of all possible language nodes have a common super class or interface `CommonSuperType`,
it should be registered in the specifics of your language in this way:

```typescript
export interface MySpecifics extends TypirSpecifics {
LanguageType: CommonSuperType;
}
```

### Language key

Each language node might have a *language key*.
Language keys are `string` values and are used to increase performance by registering rules for inference and validation not for all language nodes,
but only for language nodes with a particular language key.
Rules associated to no language key are applied to all language nodes.
Rules might be associated to multiple language keys.
Getting the language key of a language node is done by the [language service](./services/language.md).
The available language keys could be restricted by customizing the specifics of your language in this way:

```typescript
export type MyAstTypes = {
LanguageKey1: LanguageType1;
LanguageKey2: LanguageType2;
// ...
}

export interface MySpecifics extends TypirSpecifics {
LanguageKeys: MyAstTypes;
}
```

Even if there is no list of concrete language keys, adopters should override this property with `Record<string, CommonSuperType>`,
if the `LanguageType` is set to `CommonSuperType` (see section above):

```typescript
export interface MySpecifics extends TypirSpecifics {
LanguageKeys: Record<string, CommonSuperType>;
}
```

## Services and default implementations

- services
- (default) implementations
- Typir module in `typir.ts`: assembles services and implementations
- It is possible to group services
- Names of services start with an uppercase letter, names of groups start with a lowercase letter
- Dependency injection (DI)


## Terminology / Glossary

- inference: inference rule, type inference
- language node, language key
- ...
- cyclic dependencies
- compile time vs runtime
2 changes: 1 addition & 1 deletion documentation/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ After creating the Langium services (which contain the Typir serivces now) and s

```typescript
export interface MyDSLSpecifics extends TypirLangiumSpecifics {
AstTypes: MyDSLAstType; // all AST types from the generated `ast.ts`
LanguageKeys: MyDSLAstType; // all AST types from the generated `ast.ts`
// ... more could be customized here ...
}
```
Expand Down
1 change: 1 addition & 0 deletions documentation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This describes the structure and the main content of the documentation for Typir
- [Assignability](./services/assignability.md)
- [Language](./services/language.md): Don't interchange "language service" and "language server"!
- [Type inference](./services/inference.md)
- [Validation](./services/validation.md)
- ...


Expand Down
21 changes: 18 additions & 3 deletions documentation/services/inference.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Type inference

Type inference infers a Typir type for a given language node, i.e. it answers the question, which Tyir type has a language node.
Type inference infers a Typir type for a given language node, i.e. it answers the question, which Typir type has a language node.
Therefore type inference is the central part which connects the type system and its type graph with an AST consisting of language nodes.
These relationships are defined with *inference rules*, which identify the type for some language nodes.
These relationships are defined with *inference rules*, which identify the Typir type for a given language node.


## API
Expand All @@ -14,12 +14,27 @@ and returns either the inferred type or an (maybe empty) array with reasons, why
typir.Inference.inferType(languageNode: Specifics['LanguageType']): Type | InferenceProblem[]
```

Inference rules can be registered with this API call:
Inference rules can be registered with this API call (the `TypeInferenceRuleOptions` are the same as for [validation rules](../services/validation.md)):

```typescript
typir.Inference.addInferenceRule(rule: TypeInferenceRule, options?: TypeInferenceRuleOptions): void
```

It is possible to register multiple inference rules for language keys at once with this API:

```typescript
typir.Inference.addInferenceRulesForLanguageNodes(rules: InferenceRulesForLanguageKeys): void
```

The following example sketches, how to use this API, and shows its benefits regarding TypeScript safety (if `Specifics['LanguageKeys']` is specified):

```typescript
typir.Inference.addInferenceRulesForLanguageNodes({
'VariableDeclaration': (languageNode /* is of type VariableDeclaration */) => languageNode.value,
'VariableUsage': (languageNode /* is of type VariableUsage */) => languageNode.ref,
// ...
});
```

## Default implementation

Expand Down
2 changes: 1 addition & 1 deletion documentation/services/language.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ these rules are applied only to those language nodes which have this language ke
It is possible to associate rules to multiple language keys.
Rules which are associated to no language key, are applied to all language nodes.

Language keys are represented by string values and might be depending on the DSL implementation/language workbench,
Language keys are represented by `string` values and might be depending on the DSL implementation/language workbench,
class names or `$type`-property-information of the language node implementations.
Language keys might have sub/super language keys ("sub-type relationship of language keys").

Expand Down
Loading