Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring: Define Blocktypes solely in Code #445

Merged
merged 45 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ab785d9
Document constraint types in-code
georg-schwarz Sep 4, 2023
977d42f
Separate block and constraint meta inf registries
georg-schwarz Sep 4, 2023
d2dc2ca
Started refactoring BlockMetaInformation to be a wrapper instead of …
georg-schwarz Sep 4, 2023
ff1dacb
Adapt tests to removal of extensions
georg-schwarz Sep 4, 2023
a1f5ffe
Replace lang extensions by builtin blocktype definitions
georg-schwarz Sep 4, 2023
249c856
Fix build and linter of remaining apps/libs
georg-schwarz Sep 5, 2023
8f9da7e
Remove test.jv
georg-schwarz Sep 5, 2023
27d62f1
Move validations from ArchiveInterpreter to property assignment valid…
georg-schwarz Sep 5, 2023
4f26f7d
Move validations from CellWriter to property assignment validations
georg-schwarz Sep 5, 2023
575cad4
Move validations from ColumnDeleter to property assignment validations
georg-schwarz Sep 5, 2023
8e8c185
Move validations from GtfsRTInterpreter to property assignment valida…
georg-schwarz Sep 5, 2023
4363920
Test ArchiveInterpreter custom validation
georg-schwarz Sep 5, 2023
d8a5605
Fix too eager validation
georg-schwarz Sep 5, 2023
72866d5
Move validations from HttpExtractor to property assignment validations
georg-schwarz Sep 6, 2023
529f928
Move validations from RowDeleter to property assignment validations
georg-schwarz Sep 6, 2023
d73e1d7
Move validations from TableInterpreter to property assignment validat…
georg-schwarz Sep 6, 2023
e392224
Move validations from TextFileInterpreter to property assignment vali…
georg-schwarz Sep 6, 2023
bd50a8e
Move validations from TextLineDeleter to property assignment validations
georg-schwarz Sep 6, 2023
cc2a58d
Move validations from TextRangeSelector to property assignment valida…
georg-schwarz Sep 6, 2023
8cb933c
Refactor blocktype specific property validations into own file
georg-schwarz Sep 6, 2023
8536b44
Pull out checkPropertyValueOneOf function
georg-schwarz Sep 6, 2023
2a5d826
Move body validations from TextRangeSelector to property body validat…
georg-schwarz Sep 7, 2023
f087692
Move body validations from CellWriter to property body validations
georg-schwarz Sep 7, 2023
a3861f9
Move body validations from TableTransformer to property body validations
georg-schwarz Sep 7, 2023
d249c7e
Move body validations from TableTransformer to property body validations
georg-schwarz Sep 7, 2023
6337d40
Resolve TODO in runtime parameter literal validation
georg-schwarz Sep 7, 2023
7fec953
Remove TODO in BlockMetaInformation
georg-schwarz Sep 7, 2023
f812028
Iterate over all registered blocktypes where necessary with new way
georg-schwarz Sep 7, 2023
80d0a0b
Implement BlockMetaInformation.canBeWrapped
georg-schwarz Sep 7, 2023
718316c
Generate documentation of blocktype and examples from blocktype defin…
georg-schwarz Sep 7, 2023
55abaa6
Add documentation for properties of blocktypes reading from jv comment
georg-schwarz Sep 7, 2023
ca72b28
Pull out method extractDocsFromComment
georg-schwarz Sep 7, 2023
d0ad929
Improve assertion messages
georg-schwarz Sep 7, 2023
18a761c
Merge branch 'main' into block-meta-inf-in-code
georg-schwarz Sep 7, 2023
9acd943
Use default JSdocProvider
georg-schwarz Sep 26, 2023
a21ccc6
Implement utility function getMetaInformation
georg-schwarz Sep 26, 2023
8d7bc1a
Remove JayveeDocumentationProvider
georg-schwarz Sep 26, 2023
7932bd9
Fix linter and test
georg-schwarz Sep 26, 2023
4cd0a78
Pull out function getAllBuiltinBlocktypes
georg-schwarz Sep 26, 2023
2e64c22
Update docs
georg-schwarz Sep 26, 2023
e3caa48
Add missing license headers
georg-schwarz Sep 26, 2023
48b883c
Remove info box from docs
georg-schwarz Nov 2, 2023
7d98ae4
Ignore duplicates in getAllBuiltinBlocktypes
georg-schwarz Nov 2, 2023
b5bddfd
Merge branch 'main' into block-meta-inf-in-code
georg-schwarz Nov 2, 2023
57ee14d
Adapt tests to changes
georg-schwarz Nov 2, 2023
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
135 changes: 23 additions & 112 deletions apps/docs/docs/dev/04-guides/06-jayvee-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,53 +15,38 @@ Jayvee extensions that shall be used by default are bundled into the so-called [

A language extension defines meta information of block types which are required by the
[language server](https://github.com/jvalue/jayvee/tree/main/libs/language-server).
Such meta information describes properties of
Such meta information describes properties of
block types such as their names, input / output types and their properties.

Note that language extensions don't define any behavior. Instead, this is done by the corresponding execution extension.

### Execution extension

An execution extension defines behavior for block types. They build on the meta information from the corresponding
language extension, e.g. input / output types of the block need to match the signature of the execution method and
An execution extension defines behavior for block types. They build on the meta information from the corresponding
language extension, e.g. input / output types of the block need to match the signature of the execution method and
properties are accessed by their specified name.

Execution extensions are only required by the [interpreter](https://github.com/jvalue/jayvee/tree/main/apps/interpreter) and not necessarily by the [language server](https://github.com/jvalue/jayvee/tree/main/libs/language-server) as they solely define behavior.

## Recipes

### Add a new Jayvee extension
### Add a new Jayvee execution extension

#### 1. Generate language and execution libraries
#### 1. Generate an execution libraries

```bash
npx nx g @nrwl/node:library --name="extensions/<extension-name>/lang"
npx nx g @nrwl/node:library --name="extensions/<extension-name>/exec"
```

#### 2. Create extension classes

In `libs/extensions/<extension-name>/lang/src/extension.ts`:

```typescript
import {
BlockMetaInformation,
ConstructorClass,
JayveeLangExtension,
} from '@jvalue/jayvee-language-server';

export class MyLangExtension implements JayveeLangExtension {
getBlockMetaInf(): Array<ConstructorClass<BlockMetaInformation>> {
return [];
}
}

```

In `libs/extensions/<extension-name>/exec/src/extension.ts`:

```typescript
import { BlockExecutorClass, JayveeExecExtension } from '@jvalue/jayvee-execution';
import {
BlockExecutorClass,
JayveeExecExtension,
} from '@jvalue/jayvee-execution';

export class MyExecExtension implements JayveeExecExtension {
getBlockExecutors(): BlockExecutorClass[] {
Expand All @@ -72,12 +57,6 @@ export class MyExecExtension implements JayveeExecExtension {

#### 3. Export extension classes

In `libs/extensions/<extension-name>/lang/src/index.ts`:

```typescript
export * from './extension';
```

In `libs/extensions/<extension-name>/exec/src/index.ts`:

```typescript
Expand All @@ -86,25 +65,6 @@ export * from './extension';

#### 4. Register new extension classes in the standard extension

In `libs/extensions/std/lang/src/extension.ts`:

```typescript
// ...

import { MyLangExtension } from '@jvalue/jayvee-extensions/<extension-name>/lang';

export class StdLangExtension implements JayveeLangExtension {
private readonly wrappedExtensions: JayveeLangExtension[] = [
// ...
// Register your language extension here:
new MyLangExtension(),
// ...
];

// ...
}
```

In `libs/extensions/std/exec/src/extension.ts`:

```typescript
Expand All @@ -126,77 +86,28 @@ export class StdExecExtension implements JayveeExecExtension {

### Add a new block type in a Jayvee extension

#### 1. Implement `BlockMetaInformation`
#### 1. Create a builtin blocktype

The following example defines a block type called `MyExtractor`. This block type, for instance, takes no input and
outputs a sheet. Furthermore, it defines two properties:
Define the syntax of the new blocktype in the [language server's builtin blocktypes](https://github.com/jvalue/jayvee/tree/main/libs/language-server/src/stdlib/builtin-blocktypes).

- `url` of type text
- `limit` of type integer and default value `10`
- Considered optional due to the specified default value
The following example defines a block type `MyExtractor` with a text property called `url` and a property `retries` with a default value:

In `libs/extensions/<extension-name>/lang/src/lib/my-extractor-meta-inf.ts`:
```jayvee
builtin blocktype MyExtractor {
input default oftype None;
output default oftype Sheet;

```typescript
import {
BlockMetaInformation,
IOType,
PrimitiveValuetypes,
} from '@jvalue/jayvee-language-server';

export class MyExtractorMetaInformation extends BlockMetaInformation {
constructor() {
super(
// How the block type should be called:
'MyExtractor',

// Property definitions:
{
url: {
type: PrimitiveValuetypes.Text,
},
limit: {
type: PrimitiveValuetypes.Integer,
defaultValue: 10,
},
},

// Input type:
IOType.NONE,

// Output type:
IOType.SHEET,
);
}
property url oftype text;
property retries oftype interger: 10;
}
```

> **Note**
> Use `IOType.NONE` whenever you expect no input or output:
>
> - Use it as input type if you want to define an extractor
> - Use it as output type if you want to define a loader

#### 2. Register the new `BlockMetaInformation` in the language extension
The new block type will be automatically registered on the language server startup.

In `libs/extensions/<extension-name>/lang/src/extension.ts`:
#### 2. Add custom validation logic (if required)

```typescript
// ...

import { MyExtractorMetaInformation } from './lib/my-extractor-meta-inf';
If the block type and/or its properties requires custom validation logic, you can implement it in the [language server's block type specific checks](https://github.com/jvalue/jayvee/tree/main/libs/language-server/src/lib/validation/checks/blocktype-specific).

export class MyLangExtension implements JayveeLangExtension {
getBlockMetaInf(): Array<ConstructorClass<BlockMetaInformation>> {
return [
// ...
// Register your meta information here:
MyExtractorMetaInformation,
// ...
];
}
}
```

#### 3. Implement `BlockExecutor`

Expand All @@ -223,7 +134,7 @@ export class MyExtractorExecutor
{
// Needs to match the type in meta information:
public static readonly type = 'MyExtractor';

public readonly inputType = IOType.NONE;
public readonly outputType = IOType.SHEET;

Expand All @@ -240,7 +151,7 @@ export class MyExtractorExecutor
'limit',
PrimitiveValuetypes.Integer,
);

// ...

if (error) {
Expand Down
55 changes: 36 additions & 19 deletions apps/docs/generator/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,38 @@
import { readFileSync, readdirSync, writeFileSync } from 'fs';
import { join } from 'path';

import { StdLangExtension } from '@jvalue/jayvee-extensions/std/lang';
import {
JayveeServices,
PrimitiveValuetypes,
getRegisteredBlockMetaInformation,
createJayveeServices,
getAllBuiltinBlocktypes,
getRegisteredConstraintMetaInformation,
registerConstraints,
useExtension,
initializeWorkspace,
} from '@jvalue/jayvee-language-server';
import { NodeFileSystem } from 'langium/node';

import { UserDocGenerator } from './user-doc-generator';

useExtension(new StdLangExtension());

function main(): void {
async function main(): Promise<void> {
const rootPath = join(__dirname, '..', '..', '..', '..');
generateBlockTypeDocs(rootPath);
generateConstraintTypeDocs(rootPath);
generateValueTypeDocs(rootPath);

const services = createJayveeServices(NodeFileSystem).Jayvee;
await initializeWorkspace(services);

generateBlockTypeDocs(services, rootPath);
generateConstraintTypeDocs(services, rootPath);
generateValueTypeDocs(services, rootPath);
generateExampleDocs(rootPath);
}

function generateBlockTypeDocs(rootPath: string): void {
function generateBlockTypeDocs(
services: JayveeServices,
rootPath: string,
): void {
const metaInfs = getAllBuiltinBlocktypes(
services.shared.workspace.LangiumDocuments,
);

const docsPath = join(
rootPath,
'apps',
Expand All @@ -35,9 +45,9 @@ function generateBlockTypeDocs(rootPath: string): void {
'user',
'block-types',
);
const metaInfs = getRegisteredBlockMetaInformation();

for (const metaInf of metaInfs) {
const userDocBuilder = new UserDocGenerator();
const userDocBuilder = new UserDocGenerator(services);
const blockTypeDoc = userDocBuilder.generateBlockTypeDoc(metaInf);

const fileName = `${metaInf.type}.md`;
Expand All @@ -48,7 +58,10 @@ function generateBlockTypeDocs(rootPath: string): void {
}
}

function generateConstraintTypeDocs(rootPath: string): void {
function generateConstraintTypeDocs(
services: JayveeServices,
rootPath: string,
): void {
const docsPath = join(
rootPath,
'apps',
Expand All @@ -57,11 +70,10 @@ function generateConstraintTypeDocs(rootPath: string): void {
'user',
'constraint-types',
);
registerConstraints();
const metaInfs = getRegisteredConstraintMetaInformation();

for (const metaInf of metaInfs) {
const userDocBuilder = new UserDocGenerator();
const userDocBuilder = new UserDocGenerator(services);
const blockTypeDoc = userDocBuilder.generateConstraintTypeDoc(metaInf);

const fileName = `${metaInf.type}.md`;
Expand All @@ -72,9 +84,12 @@ function generateConstraintTypeDocs(rootPath: string): void {
}
}

function generateValueTypeDocs(rootPath: string): void {
function generateValueTypeDocs(
services: JayveeServices,
rootPath: string,
): void {
const docsPath = join(rootPath, 'apps', 'docs', 'docs', 'user', 'valuetypes');
const userDocBuilder = new UserDocGenerator();
const userDocBuilder = new UserDocGenerator(services);
const valueTypeDoc =
userDocBuilder.generateValueTypesDoc(PrimitiveValuetypes);

Expand Down Expand Up @@ -113,4 +128,6 @@ ${exampleModel.toString()}
}
}

main();
main()
.then(() => console.log('Finished generating docs!'))
.catch((e) => console.error(e));
Loading
Loading