From ab785d90527d534cc4f83d198018a563a46ea4a8 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Mon, 4 Sep 2023 14:08:01 +0200 Subject: [PATCH 01/43] Document constraint types in-code --- .../standard-library-file-system-provider.ts | 2 + .../constraint-executor-registry.ts | 3 +- .../runtime-parameter-literal.ts | 4 +- .../src/grammar/constraint.langium | 11 +-- libs/language-server/src/grammar/main.langium | 1 + .../src/lib/builtin-library/stdlib.ts | 71 ++++++++++++++++++- .../completion/jayvee-completion-provider.ts | 5 +- .../src/lib/hover/jayvee-hover-provider.ts | 15 ++-- .../lib/meta-information/meta-inf-registry.ts | 24 ++++--- .../checks/typed-constraint-definition.ts | 2 +- .../validation/checks/valuetype-reference.ts | 9 +-- 11 files changed, 115 insertions(+), 32 deletions(-) diff --git a/apps/vs-code-extension/src/standard-library-file-system-provider.ts b/apps/vs-code-extension/src/standard-library-file-system-provider.ts index 0f1086ca6..862ff9eaa 100644 --- a/apps/vs-code-extension/src/standard-library-file-system-provider.ts +++ b/apps/vs-code-extension/src/standard-library-file-system-provider.ts @@ -5,6 +5,7 @@ import { StdLangExtension } from '@jvalue/jayvee-extensions/std/lang'; import { getStdLib, + registerConstraints, useExtension as useLangExtension, } from '@jvalue/jayvee-language-server'; import { @@ -34,6 +35,7 @@ export class StandardLibraryFileSystemProvider implements FileSystemProvider { // The VSCode Extension needs to register the StdLangExtension, // otherwise the StdLib does not include the blocktype definitions. useLangExtension(new StdLangExtension()); + registerConstraints(); Object.entries(getStdLib()).forEach(([libName, lib]) => { this.libraries.set( diff --git a/libs/execution/src/lib/constraints/constraint-executor-registry.ts b/libs/execution/src/lib/constraints/constraint-executor-registry.ts index 7b7e22175..2929f230b 100644 --- a/libs/execution/src/lib/constraints/constraint-executor-registry.ts +++ b/libs/execution/src/lib/constraints/constraint-executor-registry.ts @@ -46,7 +46,8 @@ export function createConstraintExecutor( constraint: ConstraintDefinition, ): ConstraintExecutor { if (isTypedConstraintDefinition(constraint)) { - const constraintType = constraint.type.name; + const constraintType = constraint.type.ref?.name; + assert(constraintType !== undefined); const constraintExecutor = constraintExecutorRegistry.get(constraintType); assert( constraintExecutor !== undefined, diff --git a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts index 35d29d9df..968d34463 100644 --- a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts +++ b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts @@ -3,7 +3,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { - ConstraintTypeLiteral, + BuiltinConstrainttypeDefinition, EvaluationContext, PropertyBody, ReferenceableBlocktypeDefinition, @@ -63,7 +63,7 @@ function checkRuntimeParameterValueParsing( const enclosingPropertyBody = getEnclosingPropertyBody(runtimeParameter); const type: | Reference - | ConstraintTypeLiteral + | Reference | undefined = // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition enclosingPropertyBody.$container?.type; diff --git a/libs/language-server/src/grammar/constraint.langium b/libs/language-server/src/grammar/constraint.langium index 2d7fb6ecf..54bd119be 100644 --- a/libs/language-server/src/grammar/constraint.langium +++ b/libs/language-server/src/grammar/constraint.langium @@ -11,12 +11,15 @@ ConstraintDefinition: TypedConstraintDefinition | ExpressionConstraintDefinition; TypedConstraintDefinition: - 'constraint' name=ID 'oftype' type=ConstraintTypeLiteral body=PropertyBody; + 'constraint' name=ID 'oftype' type=[BuiltinConstrainttypeDefinition] body=PropertyBody; ExpressionConstraintDefinition: 'constraint' name=ID 'on' valuetype=ValuetypeReference ':' expression=Expression ';'; +BuiltinConstrainttypeDefinition: + 'builtin' 'constrainttype' name=ID '{' + (properties+=ConstrainttypeProperty)* +'}'; -ConstraintTypeLiteral: - name=ID; - +ConstrainttypeProperty: + 'property' name=ID 'oftype' valueType=ValuetypeReference (':' defaultValue=Expression)? ';'; \ No newline at end of file diff --git a/libs/language-server/src/grammar/main.langium b/libs/language-server/src/grammar/main.langium index 602f0e542..46097adcb 100644 --- a/libs/language-server/src/grammar/main.langium +++ b/libs/language-server/src/grammar/main.langium @@ -19,6 +19,7 @@ entry JayveeModel: | constraints+=ConstraintDefinition | transforms+=TransformDefinition | blocktypes+=ReferenceableBlocktypeDefinition + | constrainttypes+=BuiltinConstrainttypeDefinition | iotypes+=IotypeDefinition )*; diff --git a/libs/language-server/src/lib/builtin-library/stdlib.ts b/libs/language-server/src/lib/builtin-library/stdlib.ts index c1de56dda..8a8c84b5e 100644 --- a/libs/language-server/src/lib/builtin-library/stdlib.ts +++ b/libs/language-server/src/lib/builtin-library/stdlib.ts @@ -2,10 +2,11 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { IOType, PrimitiveValuetype } from '../ast'; +import { IOType, PrimitiveValuetype, internalValueToString } from '../ast'; import { PrimitiveValuetypes } from '../ast/wrappers/value-type/primitive/primitive-valuetypes'; import { BlockMetaInformation, + ConstraintMetaInformation, metaInformationRegistry, } from '../meta-information'; @@ -35,9 +36,9 @@ export const IOtypesLib = { // Is a method since metaInformationRegistry might not be initialized when this as variable. export function getBuiltinBlocktypesLib() { - const builtinBlocktypes = metaInformationRegistry.getAllEntries(); + const builtins = metaInformationRegistry.getAllEntries(); return { - 'builtin:///stdlib/builtin-blocktypes.jv': builtinBlocktypes + 'builtin:///stdlib/builtin-blocktypes.jv': builtins .filter((entry) => entry.value instanceof BlockMetaInformation) .map((entry) => parseBlockMetaInfToJayvee( @@ -49,12 +50,29 @@ export function getBuiltinBlocktypesLib() { }; } +// Is a method since metaInformationRegistry might not be initialized when this as variable. +export function getBuiltinConstrainttypesLib() { + const builtins = metaInformationRegistry.getAllEntries(); + return { + 'builtin:///stdlib/builtin-constrainttypes.jv': builtins + .filter((entry) => entry.value instanceof ConstraintMetaInformation) + .map((entry) => + parseConstraintMetaInfToJayvee( + entry.key, + entry.value as ConstraintMetaInformation, + ), + ) + .join('\n\n'), + }; +} + export function getStdLib() { return { ...PartialStdLib, ...getBuiltinValuetypesLib(), ...IOtypesLib, ...getBuiltinBlocktypesLib(), + ...getBuiltinConstrainttypesLib(), }; } @@ -118,6 +136,53 @@ function parseBuiltinValuetypeToJayvee(valuetype: PrimitiveValuetype): string { return lines.join('\n'); } +function parseConstraintMetaInfToJayvee( + name: string, + metaInf: ConstraintMetaInformation, +): string { + const lines: string[] = []; + if (metaInf.docs.description !== undefined) { + lines.push(parseAsComment(metaInf.docs.description)); + } + if (metaInf.docs.examples !== undefined) { + metaInf.docs.examples.forEach((example, i) => { + lines.push('//'); + lines.push(`// Example ${i + 1}: ${example.description}`); + lines.push(parseAsComment(example.code)); + }); + } + + lines.push(`builtin constrainttype ${name} {`); + lines.push(parseBuiltinConstrainttypeBody(metaInf)); + lines.push('}'); + + return lines.join('\n'); +} + +function parseBuiltinConstrainttypeBody( + metaInf: ConstraintMetaInformation, +): string { + const bodyLines: string[] = []; + + Object.entries(metaInf.getPropertySpecifications()).forEach( + ([propName, propSpecification]) => { + const propDoc = propSpecification.docs?.description; + if (propDoc !== undefined) { + bodyLines.push(parseAsComment(propDoc, 1)); + } + bodyLines.push( + `\tproperty ${propName} oftype ${propSpecification.type.getName()} ${ + propSpecification.defaultValue !== undefined + ? `: ${internalValueToString(propSpecification.defaultValue)}` + : '' + };`, + ); + }, + ); + + return bodyLines.join('\n'); +} + function parseAsComment(text: string, indents = 0): string { return text .split('\n') diff --git a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts index b85fc5828..cd287dc5a 100644 --- a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts +++ b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts @@ -20,13 +20,11 @@ import { createValuetype } from '../ast'; import { BlockDefinition, ConstraintDefinition, - ConstraintTypeLiteral, PropertyAssignment, PropertyBody, ValuetypeReference, isBlockDefinition, isConstraintDefinition, - isConstraintTypeLiteral, isJayveeModel, isPropertyAssignment, isPropertyBody, @@ -63,8 +61,7 @@ export class JayveeCompletionProvider extends DefaultCompletionProvider { } const isConstraintTypeCompletion = - (isConstraintDefinition(astNode) || isConstraintTypeLiteral(astNode)) && - next.type === ConstraintTypeLiteral; + isConstraintDefinition(astNode) && next.property === 'type'; if (isConstraintTypeCompletion) { return this.completionForConstraintType(acceptor); } diff --git a/libs/language-server/src/lib/hover/jayvee-hover-provider.ts b/libs/language-server/src/lib/hover/jayvee-hover-provider.ts index b5a8a0b6f..95ad9a28a 100644 --- a/libs/language-server/src/lib/hover/jayvee-hover-provider.ts +++ b/libs/language-server/src/lib/hover/jayvee-hover-provider.ts @@ -2,15 +2,20 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { AstNode, AstNodeHoverProvider, MaybePromise } from 'langium'; +import { + AstNode, + AstNodeHoverProvider, + MaybePromise, + isReference, +} from 'langium'; import { Hover } from 'vscode-languageserver-protocol'; import { BuiltinBlocktypeDefinition, - ConstraintTypeLiteral, + BuiltinConstrainttypeDefinition, PropertyAssignment, isBuiltinBlocktypeDefinition, - isConstraintTypeLiteral, + isBuiltinConstrainttypeDefinition, isPropertyAssignment, } from '../ast'; import { LspDocGenerator } from '../docs/lsp-doc-generator'; @@ -24,7 +29,7 @@ export class JayveeHoverProvider extends AstNodeHoverProvider { if (isBuiltinBlocktypeDefinition(astNode)) { doc = this.getBlockTypeMarkdownDoc(astNode); } - if (isConstraintTypeLiteral(astNode)) { + if (isBuiltinConstrainttypeDefinition(astNode)) { doc = this.getConstraintTypeMarkdownDoc(astNode); } if (isPropertyAssignment(astNode)) { @@ -56,7 +61,7 @@ export class JayveeHoverProvider extends AstNodeHoverProvider { } private getConstraintTypeMarkdownDoc( - constraintType: ConstraintTypeLiteral, + constraintType: BuiltinConstrainttypeDefinition, ): string | undefined { const constraintMetaInf = getMetaInformation(constraintType); if (constraintMetaInf === undefined) { diff --git a/libs/language-server/src/lib/meta-information/meta-inf-registry.ts b/libs/language-server/src/lib/meta-information/meta-inf-registry.ts index af62ad45a..347f87fd2 100644 --- a/libs/language-server/src/lib/meta-information/meta-inf-registry.ts +++ b/libs/language-server/src/lib/meta-information/meta-inf-registry.ts @@ -8,10 +8,10 @@ import { Reference, isReference } from 'langium'; import { assertUnreachable } from 'langium/lib/utils/errors'; import { - ConstraintTypeLiteral, + BuiltinConstrainttypeDefinition, ReferenceableBlocktypeDefinition, + isBuiltinConstrainttypeDefinition, isCompositeBlocktypeDefinition, - isConstraintTypeLiteral, isReferenceableBlocktypeDefinition, } from '../ast/generated/ast'; import { ConstructorClass } from '../util/constructor-class'; @@ -39,20 +39,25 @@ export function getMetaInformation( | undefined, ): BlockMetaInformation | undefined; export function getMetaInformation( - type: ConstraintTypeLiteral | undefined, + type: + | BuiltinConstrainttypeDefinition + | Reference + | undefined, ): ConstraintMetaInformation | undefined; export function getMetaInformation( type: | ReferenceableBlocktypeDefinition | Reference - | ConstraintTypeLiteral + | BuiltinConstrainttypeDefinition + | Reference | undefined, ): MetaInformation | undefined; export function getMetaInformation( type: | ReferenceableBlocktypeDefinition | Reference - | ConstraintTypeLiteral + | BuiltinConstrainttypeDefinition + | Reference | undefined, ): BlockMetaInformation | ConstraintMetaInformation | undefined { const dereferencedType = isReference(type) ? type.ref : type; @@ -80,7 +85,7 @@ export function getMetaInformation( assert(metaInf instanceof BlockMetaInformation); return metaInf; } - if (isConstraintTypeLiteral(dereferencedType)) { + if (isBuiltinConstrainttypeDefinition(dereferencedType)) { assert(metaInf instanceof ConstraintMetaInformation); return metaInf; } @@ -109,13 +114,16 @@ export function getOrFailMetaInformation( | Reference, ): BlockMetaInformation; export function getOrFailMetaInformation( - type: ConstraintTypeLiteral, + type: + | BuiltinConstrainttypeDefinition + | Reference, ): ConstraintMetaInformation; export function getOrFailMetaInformation( type: | ReferenceableBlocktypeDefinition | Reference - | ConstraintTypeLiteral, + | BuiltinConstrainttypeDefinition + | Reference, ): MetaInformation { const result = getMetaInformation(type); const typeName = diff --git a/libs/language-server/src/lib/validation/checks/typed-constraint-definition.ts b/libs/language-server/src/lib/validation/checks/typed-constraint-definition.ts index 97b17c2e0..6e4ec78df 100644 --- a/libs/language-server/src/lib/validation/checks/typed-constraint-definition.ts +++ b/libs/language-server/src/lib/validation/checks/typed-constraint-definition.ts @@ -31,7 +31,7 @@ function checkConstraintType( if (metaInf === undefined) { context.accept( 'error', - `Unknown constraint type '${constraintType.name ?? ''}'`, + `Unknown constraint type '${constraintType.$refText ?? ''}'`, { node: constraint, property: 'type', diff --git a/libs/language-server/src/lib/validation/checks/valuetype-reference.ts b/libs/language-server/src/lib/validation/checks/valuetype-reference.ts index 3dab5bd7a..84292708b 100644 --- a/libs/language-server/src/lib/validation/checks/valuetype-reference.ts +++ b/libs/language-server/src/lib/validation/checks/valuetype-reference.ts @@ -6,6 +6,7 @@ import { createValuetype } from '../../ast'; import { ValuetypeReference, isBuiltinBlocktypeDefinition, + isBuiltinConstrainttypeDefinition, } from '../../ast/generated/ast'; import { ValidationContext } from '../validation-context'; @@ -53,10 +54,10 @@ function checkIsValuetypeReferenceable( return; } - const isUsedInBuiltinBlocktype = isBuiltinBlocktypeDefinition( - valuetypeRef.$container.$container, - ); - if (isUsedInBuiltinBlocktype) { + const isUsedInBuiltinDefinition = + isBuiltinBlocktypeDefinition(valuetypeRef.$container.$container) || + isBuiltinConstrainttypeDefinition(valuetypeRef.$container.$container); + if (isUsedInBuiltinDefinition) { return; } From 977d42f99cfba8884dbc30d2d0a5c06dfd0732ae Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Mon, 4 Sep 2023 14:51:09 +0200 Subject: [PATCH 02/43] Separate block and constraint meta inf registries --- libs/execution/src/lib/execution-context.ts | 20 +-- .../runtime-parameter-literal.ts | 14 ++- .../language-server/src/lib/ast/model-util.ts | 6 +- .../src/lib/builtin-library/stdlib.ts | 23 +--- .../completion/jayvee-completion-provider.ts | 13 +- .../src/lib/constraint/constraint-registry.ts | 8 +- .../meta-inf-example-validation.spec.ts | 4 +- libs/language-server/src/lib/extension.ts | 4 +- .../src/lib/hover/jayvee-hover-provider.ts | 23 +++- .../lib/meta-information/meta-inf-registry.ts | 119 ++++++++---------- .../lib/validation/checks/block-definition.ts | 4 +- .../lib/validation/checks/pipe-definition.ts | 6 +- .../checks/property-assignment.spec.ts | 12 +- .../lib/validation/checks/property-body.ts | 28 ++++- .../checks/typed-constraint-definition.ts | 4 +- .../validation/checks/valuetype-definition.ts | 4 +- libs/language-server/src/test/utils.ts | 10 +- 17 files changed, 173 insertions(+), 129 deletions(-) diff --git a/libs/execution/src/lib/execution-context.ts b/libs/execution/src/lib/execution-context.ts index ef5f649db..05123b152 100644 --- a/libs/execution/src/lib/execution-context.ts +++ b/libs/execution/src/lib/execution-context.ts @@ -9,20 +9,21 @@ import { ConstraintDefinition, EvaluationContext, InternalValueRepresentation, - MetaInformation, PipelineDefinition, PropertyAssignment, TransformDefinition, Valuetype, evaluatePropertyValue, - getOrFailMetaInformation, - isConstraintDefinition, + getOrFailBockMetaInf, + getOrFailConstraintMetaInf, + isBlockDefinition, isExpressionConstraintDefinition, isPipelineDefinition, isPropertyBody, isTransformDefinition, + isTypedConstraintDefinition, } from '@jvalue/jayvee-language-server'; -import { isReference } from 'langium'; +import { assertUnreachable, isReference } from 'langium'; import { DebugGranularity, @@ -145,13 +146,12 @@ export class ExecutionContext { assert(!isExpressionConstraintDefinition(currentNode)); assert(!isTransformDefinition(currentNode)); - let metaInf: MetaInformation; - if (isConstraintDefinition(currentNode)) { - metaInf = getOrFailMetaInformation(currentNode.type); - } else { + if (isTypedConstraintDefinition(currentNode)) { + return getOrFailConstraintMetaInf(currentNode.type); + } else if (isBlockDefinition(currentNode)) { assert(isReference(currentNode.type)); - metaInf = getOrFailMetaInformation(currentNode.type); + return getOrFailBockMetaInf(currentNode.type); } - return metaInf; + assertUnreachable(currentNode); } } diff --git a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts index 968d34463..4561ec8e2 100644 --- a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts +++ b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts @@ -5,11 +5,15 @@ import { BuiltinConstrainttypeDefinition, EvaluationContext, + MetaInformation, PropertyBody, ReferenceableBlocktypeDefinition, RuntimeParameterLiteral, ValidationContext, - getMetaInformation, + getBlockMetaInf, + getConstraintMetaInf, + isBuiltinConstrainttypeDefinition, + isReferenceableBlocktypeDefinition, } from '@jvalue/jayvee-language-server'; import { Reference } from 'langium'; @@ -75,7 +79,13 @@ function checkRuntimeParameterValueParsing( return; } - const metaInf = getMetaInformation(type); + let metaInf: MetaInformation | undefined; + if (isReferenceableBlocktypeDefinition(type.ref)) { + metaInf = getBlockMetaInf(type.ref); + } else if (isBuiltinConstrainttypeDefinition(type.ref)) { + metaInf = getConstraintMetaInf(type.ref); + } + const propertySpec = metaInf?.getPropertySpecification(propertyName); if (propertySpec === undefined) { return; diff --git a/libs/language-server/src/lib/ast/model-util.ts b/libs/language-server/src/lib/ast/model-util.ts index 1550a8081..57b1c204f 100644 --- a/libs/language-server/src/lib/ast/model-util.ts +++ b/libs/language-server/src/lib/ast/model-util.ts @@ -7,7 +7,7 @@ import { strict as assert } from 'assert'; import { AstNode, Reference, assertUnreachable } from 'langium'; // eslint-disable-next-line import/no-cycle -import { getMetaInformation } from '../meta-information/meta-inf-registry'; +import { getBlockMetaInf } from '../meta-information/meta-inf-registry'; import { BinaryExpression, @@ -29,7 +29,7 @@ export function collectStartingBlocks( .map((blockRef: Reference | undefined) => { if ( blockRef?.ref !== undefined && - getMetaInformation(blockRef.ref.type) !== undefined + getBlockMetaInf(blockRef.ref.type) !== undefined ) { return blockRef.ref; } @@ -45,7 +45,7 @@ export function collectStartingBlocks( // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition const blocks = container?.blocks ?? []; for (const block of blocks) { - const blockMetaInf = getMetaInformation(block.type); + const blockMetaInf = getBlockMetaInf(block.type); if (blockMetaInf === undefined) { continue; } diff --git a/libs/language-server/src/lib/builtin-library/stdlib.ts b/libs/language-server/src/lib/builtin-library/stdlib.ts index 8a8c84b5e..c1032b739 100644 --- a/libs/language-server/src/lib/builtin-library/stdlib.ts +++ b/libs/language-server/src/lib/builtin-library/stdlib.ts @@ -7,7 +7,8 @@ import { PrimitiveValuetypes } from '../ast/wrappers/value-type/primitive/primit import { BlockMetaInformation, ConstraintMetaInformation, - metaInformationRegistry, + blockMetaInfRegistry, + constraintMetaInfRegistry, } from '../meta-information'; import { PartialStdLib } from './generated/partial-stdlib'; @@ -36,32 +37,20 @@ export const IOtypesLib = { // Is a method since metaInformationRegistry might not be initialized when this as variable. export function getBuiltinBlocktypesLib() { - const builtins = metaInformationRegistry.getAllEntries(); + const builtins = blockMetaInfRegistry.getAllEntries(); return { 'builtin:///stdlib/builtin-blocktypes.jv': builtins - .filter((entry) => entry.value instanceof BlockMetaInformation) - .map((entry) => - parseBlockMetaInfToJayvee( - entry.key, - entry.value as BlockMetaInformation, - ), - ) + .map((entry) => parseBlockMetaInfToJayvee(entry.key, entry.value)) .join('\n\n'), }; } // Is a method since metaInformationRegistry might not be initialized when this as variable. export function getBuiltinConstrainttypesLib() { - const builtins = metaInformationRegistry.getAllEntries(); + const builtins = constraintMetaInfRegistry.getAllEntries(); return { 'builtin:///stdlib/builtin-constrainttypes.jv': builtins - .filter((entry) => entry.value instanceof ConstraintMetaInformation) - .map((entry) => - parseConstraintMetaInfToJayvee( - entry.key, - entry.value as ConstraintMetaInformation, - ), - ) + .map((entry) => parseConstraintMetaInfToJayvee(entry.key, entry.value)) .join('\n\n'), }; } diff --git a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts index cd287dc5a..681393384 100644 --- a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts +++ b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts @@ -24,15 +24,18 @@ import { PropertyBody, ValuetypeReference, isBlockDefinition, + isBuiltinConstrainttypeDefinition, isConstraintDefinition, isJayveeModel, isPropertyAssignment, isPropertyBody, + isReferenceableBlocktypeDefinition, } from '../ast/generated/ast'; import { LspDocGenerator } from '../docs/lsp-doc-generator'; import { MetaInformation } from '../meta-information/meta-inf'; import { - getMetaInformation, + getBlockMetaInf, + getConstraintMetaInf, getRegisteredBlockMetaInformation, getRegisteredConstraintMetaInformation, } from '../meta-information/meta-inf-registry'; @@ -152,10 +155,16 @@ export class JayveeCompletionProvider extends DefaultCompletionProvider { container = astNode.$container.$container; } - const metaInf = getMetaInformation(container.type); + let metaInf: MetaInformation | undefined; + if (isReferenceableBlocktypeDefinition(container.type.ref)) { + metaInf = getBlockMetaInf(container.type.ref); + } else if (isBuiltinConstrainttypeDefinition(container.type.ref)) { + metaInf = getConstraintMetaInf(container.type.ref); + } if (metaInf === undefined) { return; } + const presentPropertyNames = container.body.properties.map( (attr) => attr.name, ); diff --git a/libs/language-server/src/lib/constraint/constraint-registry.ts b/libs/language-server/src/lib/constraint/constraint-registry.ts index aa3454e70..f2238d71d 100644 --- a/libs/language-server/src/lib/constraint/constraint-registry.ts +++ b/libs/language-server/src/lib/constraint/constraint-registry.ts @@ -3,7 +3,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { ConstraintMetaInformation } from '../meta-information'; -import { registerMetaInformation } from '../meta-information/meta-inf-registry'; +import { registerConstraintMetaInf } from '../meta-information/meta-inf-registry'; import { ConstructorClass } from '../util'; import { AllowlistConstraintMetaInformation } from './allowlist-constraint-meta-inf'; @@ -12,7 +12,7 @@ import { LengthConstraintMetaInformation } from './length-constraint-meta-inf'; import { RangeConstraintMetaInformation } from './range-constraint-meta-inf'; import { RegexConstraintMetaInformation } from './regex-constraint-meta-inf'; -export function getConstraintMetaInf(): ConstructorClass[] { +export function getAvailableConstraintMetaInf(): ConstructorClass[] { return [ AllowlistConstraintMetaInformation, DenylistConstraintMetaInformation, @@ -23,7 +23,7 @@ export function getConstraintMetaInf(): ConstructorClass { let services: JayveeServices; @@ -26,7 +26,7 @@ describe('Validation of builtin examples of ConstraintMetaInformation', () => { }); it.each( - getConstraintMetaInf().map((metaInfClass) => { + getAvailableConstraintMetaInf().map((metaInfClass) => { const metaInf = new metaInfClass(); return [metaInf.type, metaInf]; }), diff --git a/libs/language-server/src/lib/extension.ts b/libs/language-server/src/lib/extension.ts index 36fdc018d..e4a7d0799 100644 --- a/libs/language-server/src/lib/extension.ts +++ b/libs/language-server/src/lib/extension.ts @@ -3,7 +3,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { BlockMetaInformation } from './meta-information'; -import { registerMetaInformation } from './meta-information/meta-inf-registry'; +import { registerBlockMetaInf } from './meta-information/meta-inf-registry'; import { ConstructorClass } from './util/constructor-class'; export interface JayveeLangExtension { @@ -11,5 +11,5 @@ export interface JayveeLangExtension { } export function useExtension(extension: JayveeLangExtension) { - extension.getBlockMetaInf().forEach(registerMetaInformation); + extension.getBlockMetaInf().forEach(registerBlockMetaInf); } diff --git a/libs/language-server/src/lib/hover/jayvee-hover-provider.ts b/libs/language-server/src/lib/hover/jayvee-hover-provider.ts index 95ad9a28a..4dc9f07ee 100644 --- a/libs/language-server/src/lib/hover/jayvee-hover-provider.ts +++ b/libs/language-server/src/lib/hover/jayvee-hover-provider.ts @@ -6,7 +6,7 @@ import { AstNode, AstNodeHoverProvider, MaybePromise, - isReference, + assertUnreachable, } from 'langium'; import { Hover } from 'vscode-languageserver-protocol'; @@ -14,12 +14,18 @@ import { BuiltinBlocktypeDefinition, BuiltinConstrainttypeDefinition, PropertyAssignment, + isBlockDefinition, isBuiltinBlocktypeDefinition, isBuiltinConstrainttypeDefinition, isPropertyAssignment, + isTypedConstraintDefinition, } from '../ast'; import { LspDocGenerator } from '../docs/lsp-doc-generator'; -import { getMetaInformation } from '../meta-information'; +import { + MetaInformation, + getBlockMetaInf, + getConstraintMetaInf, +} from '../meta-information'; export class JayveeHoverProvider extends AstNodeHoverProvider { override getAstNodeHoverContent( @@ -51,7 +57,7 @@ export class JayveeHoverProvider extends AstNodeHoverProvider { private getBlockTypeMarkdownDoc( blockType: BuiltinBlocktypeDefinition, ): string | undefined { - const blockMetaInf = getMetaInformation(blockType); + const blockMetaInf = getBlockMetaInf(blockType); if (blockMetaInf === undefined) { return; } @@ -63,7 +69,7 @@ export class JayveeHoverProvider extends AstNodeHoverProvider { private getConstraintTypeMarkdownDoc( constraintType: BuiltinConstrainttypeDefinition, ): string | undefined { - const constraintMetaInf = getMetaInformation(constraintType); + const constraintMetaInf = getConstraintMetaInf(constraintType); if (constraintMetaInf === undefined) { return; } @@ -76,7 +82,14 @@ export class JayveeHoverProvider extends AstNodeHoverProvider { property: PropertyAssignment, ): string | undefined { const block = property.$container.$container; - const metaInf = getMetaInformation(block.type); + let metaInf: MetaInformation | undefined; + if (isTypedConstraintDefinition(block)) { + metaInf = getConstraintMetaInf(block.type); + } else if (isBlockDefinition(block)) { + metaInf = getBlockMetaInf(block.type); + } else { + assertUnreachable(block); + } if (metaInf === undefined) { return; } diff --git a/libs/language-server/src/lib/meta-information/meta-inf-registry.ts b/libs/language-server/src/lib/meta-information/meta-inf-registry.ts index 347f87fd2..262d62a0d 100644 --- a/libs/language-server/src/lib/meta-information/meta-inf-registry.ts +++ b/libs/language-server/src/lib/meta-information/meta-inf-registry.ts @@ -5,14 +5,11 @@ import { strict as assert } from 'assert'; import { Reference, isReference } from 'langium'; -import { assertUnreachable } from 'langium/lib/utils/errors'; import { BuiltinConstrainttypeDefinition, ReferenceableBlocktypeDefinition, - isBuiltinConstrainttypeDefinition, isCompositeBlocktypeDefinition, - isReferenceableBlocktypeDefinition, } from '../ast/generated/ast'; import { ConstructorClass } from '../util/constructor-class'; import { Registry } from '../util/registry'; @@ -21,45 +18,31 @@ import { Registry } from '../util/registry'; import { BlockMetaInformation } from './block-meta-inf'; import { CompositeBlocktypeMetaInformation } from './composite-blocktype-meta-inf'; import { ConstraintMetaInformation } from './constraint-meta-inf'; -import { MetaInformation } from './meta-inf'; -export const metaInformationRegistry = new Registry(); +export const blockMetaInfRegistry = new Registry(); +export const constraintMetaInfRegistry = + new Registry(); -export function registerMetaInformation( - metaInfClass: ConstructorClass, +export function registerBlockMetaInf( + metaInfClass: ConstructorClass, ) { const metaInf = new metaInfClass(); - metaInformationRegistry.register(metaInf.type, metaInf); + blockMetaInfRegistry.register(metaInf.type, metaInf); } -export function getMetaInformation( - type: - | ReferenceableBlocktypeDefinition - | Reference - | undefined, -): BlockMetaInformation | undefined; -export function getMetaInformation( - type: - | BuiltinConstrainttypeDefinition - | Reference - | undefined, -): ConstraintMetaInformation | undefined; -export function getMetaInformation( - type: - | ReferenceableBlocktypeDefinition - | Reference - | BuiltinConstrainttypeDefinition - | Reference - | undefined, -): MetaInformation | undefined; -export function getMetaInformation( +export function registerConstraintMetaInf( + metaInfClass: ConstructorClass, +) { + const metaInf = new metaInfClass(); + constraintMetaInfRegistry.register(metaInf.type, metaInf); +} + +export function getBlockMetaInf( type: | ReferenceableBlocktypeDefinition | Reference - | BuiltinConstrainttypeDefinition - | Reference | undefined, -): BlockMetaInformation | ConstraintMetaInformation | undefined { +): BlockMetaInformation | undefined { const dereferencedType = isReference(type) ? type.ref : type; if (dereferencedType === undefined) { return undefined; @@ -68,69 +51,75 @@ export function getMetaInformation( // Register meta information about composite blocks from jv code if ( isCompositeBlocktypeDefinition(dereferencedType) && - !metaInformationRegistry.get(dereferencedType.name) + !blockMetaInfRegistry.get(dereferencedType.name) ) { - metaInformationRegistry.register( + blockMetaInfRegistry.register( dereferencedType.name, new CompositeBlocktypeMetaInformation(dereferencedType), ); } - const metaInf = metaInformationRegistry.get(dereferencedType.name); + const metaInf = blockMetaInfRegistry.get(dereferencedType.name); if (metaInf === undefined) { return undefined; } - if (isReferenceableBlocktypeDefinition(dereferencedType)) { - assert(metaInf instanceof BlockMetaInformation); - return metaInf; + return metaInf; +} + +export function getConstraintMetaInf( + type: + | BuiltinConstrainttypeDefinition + | Reference + | undefined, +): ConstraintMetaInformation | undefined { + const dereferencedType = isReference(type) ? type.ref : type; + if (dereferencedType === undefined) { + return undefined; } - if (isBuiltinConstrainttypeDefinition(dereferencedType)) { - assert(metaInf instanceof ConstraintMetaInformation); - return metaInf; + + const metaInf = constraintMetaInfRegistry.get(dereferencedType.name); + if (metaInf === undefined) { + return undefined; } - assertUnreachable(dereferencedType); + + return metaInf; } export function getRegisteredBlockMetaInformation(): BlockMetaInformation[] { - return metaInformationRegistry - .getAll() - .filter( - (metaInf) => metaInf instanceof BlockMetaInformation, - ) as BlockMetaInformation[]; + return blockMetaInfRegistry.getAll(); } export function getRegisteredConstraintMetaInformation(): ConstraintMetaInformation[] { - return metaInformationRegistry - .getAll() - .filter( - (metaInf) => metaInf instanceof ConstraintMetaInformation, - ) as ConstraintMetaInformation[]; + return constraintMetaInfRegistry.getAll(); } -export function getOrFailMetaInformation( +export function getOrFailBockMetaInf( type: | ReferenceableBlocktypeDefinition | Reference, -): BlockMetaInformation; -export function getOrFailMetaInformation( - type: - | BuiltinConstrainttypeDefinition - | Reference, -): ConstraintMetaInformation; -export function getOrFailMetaInformation( +): BlockMetaInformation { + const result = getBlockMetaInf(type); + const typeName = + (isReference(type) ? type.ref?.name : type.name) ?? ''; + assert( + result !== undefined, + `Meta information for blocktype ${typeName} was expected to be present, got undefined instead`, + ); + return result; +} + +export function getOrFailConstraintMetaInf( type: - | ReferenceableBlocktypeDefinition - | Reference | BuiltinConstrainttypeDefinition | Reference, -): MetaInformation { - const result = getMetaInformation(type); +): ConstraintMetaInformation { + const result = getConstraintMetaInf(type); const typeName = (isReference(type) ? type.ref?.name : type.name) ?? ''; assert( result !== undefined, - `Meta information for type ${typeName} was expected to be present, got undefined instead`, + `Meta information for constrainttype ${typeName} was expected to be present, got undefined instead`, ); return result; } diff --git a/libs/language-server/src/lib/validation/checks/block-definition.ts b/libs/language-server/src/lib/validation/checks/block-definition.ts index f71f022e6..52d05bd8a 100644 --- a/libs/language-server/src/lib/validation/checks/block-definition.ts +++ b/libs/language-server/src/lib/validation/checks/block-definition.ts @@ -18,7 +18,7 @@ import { collectOutgoingPipes, } from '../../ast/model-util'; import { PipeWrapper } from '../../ast/wrappers/pipe-wrapper'; -import { getMetaInformation } from '../../meta-information/meta-inf-registry'; +import { getBlockMetaInf } from '../../meta-information/meta-inf-registry'; import { ValidationContext } from '../validation-context'; export function validateBlockDefinition( @@ -34,7 +34,7 @@ function checkPipesOfBlock( whatToCheck: 'input' | 'output', context: ValidationContext, ): void { - const blockMetaInf = getMetaInformation(block?.type); + const blockMetaInf = getBlockMetaInf(block?.type); if (blockMetaInf === undefined) { return; } diff --git a/libs/language-server/src/lib/validation/checks/pipe-definition.ts b/libs/language-server/src/lib/validation/checks/pipe-definition.ts index 6428c6069..523563813 100644 --- a/libs/language-server/src/lib/validation/checks/pipe-definition.ts +++ b/libs/language-server/src/lib/validation/checks/pipe-definition.ts @@ -9,7 +9,7 @@ import { PipeDefinition } from '../../ast/generated/ast'; import { createSemanticPipes } from '../../ast/wrappers/pipe-wrapper'; -import { getMetaInformation } from '../../meta-information/meta-inf-registry'; +import { getBlockMetaInf } from '../../meta-information/meta-inf-registry'; import { ValidationContext } from '../validation-context'; export function validatePipeDefinition( @@ -28,9 +28,9 @@ function checkBlockCompatibility( const fromBlockType = semanticPipe.from?.type; const toBlockType = semanticPipe.to?.type; - const fromBlockMetaInf = getMetaInformation(fromBlockType); + const fromBlockMetaInf = getBlockMetaInf(fromBlockType); - const toBlockMetaInf = getMetaInformation(toBlockType); + const toBlockMetaInf = getBlockMetaInf(toBlockType); if (fromBlockMetaInf === undefined || toBlockMetaInf === undefined) { continue; diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index afc0aabac..b17b2fd22 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -13,7 +13,10 @@ import { RuntimeParameterProvider, ValidationContext, createJayveeServices, - getMetaInformation, + getBlockMetaInf, + getConstraintMetaInf, + isBuiltinConstrainttypeDefinition, + isReferenceableBlocktypeDefinition, useExtension, } from '../../../lib'; import { @@ -52,7 +55,12 @@ describe('Validation of PropertyAssignment', () => { ) as PropertyBody; const type = propertyBody.$container.type; - const metaInf = getMetaInformation(type); + let metaInf: MetaInformation | undefined; + if (isReferenceableBlocktypeDefinition(type.ref)) { + metaInf = getBlockMetaInf(type.ref); + } else if (isBuiltinConstrainttypeDefinition(type.ref)) { + metaInf = getConstraintMetaInf(type.ref); + } expect(metaInf === undefined); const propertyAssignment = locator.getAstNode( diff --git a/libs/language-server/src/lib/validation/checks/property-body.ts b/libs/language-server/src/lib/validation/checks/property-body.ts index 224bf38b6..1db600192 100644 --- a/libs/language-server/src/lib/validation/checks/property-body.ts +++ b/libs/language-server/src/lib/validation/checks/property-body.ts @@ -7,10 +7,20 @@ */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ +import { assertUnreachable } from 'langium'; + import { EvaluationContext } from '../../ast/expressions/evaluation'; -import { PropertyAssignment, PropertyBody } from '../../ast/generated/ast'; +import { + PropertyAssignment, + PropertyBody, + isBuiltinConstrainttypeDefinition, + isReferenceableBlocktypeDefinition, +} from '../../ast/generated/ast'; import { MetaInformation } from '../../meta-information/meta-inf'; -import { getMetaInformation } from '../../meta-information/meta-inf-registry'; +import { + getBlockMetaInf, + getConstraintMetaInf, +} from '../../meta-information/meta-inf-registry'; import { ValidationContext } from '../validation-context'; import { checkUniqueNames } from '../validation-util'; @@ -58,8 +68,18 @@ export function validatePropertyBody( function inferMetaInformation( propertyBody: PropertyBody, ): MetaInformation | undefined { - const type = propertyBody.$container?.type; - return getMetaInformation(type); + const type = propertyBody.$container?.type.ref; + if (type === undefined) { + return undefined; + } + + if (isBuiltinConstrainttypeDefinition(type)) { + return getConstraintMetaInf(type); + } else if (isReferenceableBlocktypeDefinition(type)) { + return getBlockMetaInf(type); + } + + assertUnreachable(type); } function checkPropertyCompleteness( diff --git a/libs/language-server/src/lib/validation/checks/typed-constraint-definition.ts b/libs/language-server/src/lib/validation/checks/typed-constraint-definition.ts index 6e4ec78df..bfbe32c31 100644 --- a/libs/language-server/src/lib/validation/checks/typed-constraint-definition.ts +++ b/libs/language-server/src/lib/validation/checks/typed-constraint-definition.ts @@ -8,7 +8,7 @@ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ import { TypedConstraintDefinition } from '../../ast/generated/ast'; -import { getMetaInformation } from '../../meta-information/meta-inf-registry'; +import { getConstraintMetaInf } from '../../meta-information/meta-inf-registry'; import { ValidationContext } from '../validation-context'; export function validateTypedConstraintDefinition( @@ -27,7 +27,7 @@ function checkConstraintType( return undefined; } - const metaInf = getMetaInformation(constraintType); + const metaInf = getConstraintMetaInf(constraintType); if (metaInf === undefined) { context.accept( 'error', diff --git a/libs/language-server/src/lib/validation/checks/valuetype-definition.ts b/libs/language-server/src/lib/validation/checks/valuetype-definition.ts index 26d7c72e9..53ff80031 100644 --- a/libs/language-server/src/lib/validation/checks/valuetype-definition.ts +++ b/libs/language-server/src/lib/validation/checks/valuetype-definition.ts @@ -28,7 +28,7 @@ import { ValuetypeDefinition, ValuetypeGenericDefinition, } from '../../ast/generated/ast'; -import { getMetaInformation } from '../../meta-information/meta-inf-registry'; +import { getConstraintMetaInf } from '../../meta-information/meta-inf-registry'; import { ValidationContext } from '../validation-context'; export function validateValuetypeDefinition( @@ -144,7 +144,7 @@ function getCompatibleValuetype( constraint: ConstraintDefinition, ): Valuetype | undefined { if (isTypedConstraintDefinition(constraint)) { - const constraintMetaInf = getMetaInformation(constraint?.type); + const constraintMetaInf = getConstraintMetaInf(constraint?.type); return constraintMetaInf?.compatibleValuetype; } else if (isExpressionConstraintDefinition(constraint)) { return createValuetype(constraint?.valuetype); diff --git a/libs/language-server/src/test/utils.ts b/libs/language-server/src/test/utils.ts index c861c3682..4242129f9 100644 --- a/libs/language-server/src/test/utils.ts +++ b/libs/language-server/src/test/utils.ts @@ -7,7 +7,12 @@ import * as path from 'path'; import { AstNode, LangiumDocument, ValidationAcceptor } from 'langium'; -import { BlockMetaInformation, IOType, metaInformationRegistry } from '../lib'; +import { + BlockMetaInformation, + IOType, + blockMetaInfRegistry, + constraintMetaInfRegistry, +} from '../lib'; import { TestLangExtension } from './extension'; @@ -58,5 +63,6 @@ export function getTestExtensionBlockForIOType( } export function clearMetaInfRegistry() { - metaInformationRegistry.clear(); + blockMetaInfRegistry.clear(); + constraintMetaInfRegistry.clear(); } From d2dc2ca8ef75162dac1b96394a7d279c16a416c8 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Mon, 4 Sep 2023 15:44:49 +0200 Subject: [PATCH 03/43] Started refactoring BlockMetaInformation to be a wrapper instead of a registry item --- .../runtime-parameter-literal.ts | 7 +- .../language-server/src/lib/ast/model-util.ts | 8 +- .../src/lib/ast/value-definition.spec.ts | 4 +- .../src/lib/builtin-library/stdlib.ts | 58 --- .../completion/jayvee-completion-provider.ts | 7 +- .../length-constraint-meta-inf.spec.ts | 6 +- .../meta-inf-example-validation.spec.ts | 6 +- .../range-constraint-meta-inf.spec.ts | 6 +- .../src/lib/hover/jayvee-hover-provider.ts | 21 +- libs/language-server/src/lib/index.ts | 1 - .../lib/meta-information/block-meta-inf.ts | 75 +++- .../composite-blocktype-meta-inf.ts | 29 +- .../src/lib/meta-information/index.ts | 1 + .../checks/block-definition.spec.ts | 6 +- .../lib/validation/checks/block-definition.ts | 6 +- .../checks/blocktype-definition.spec.ts | 6 +- .../lib/validation/checks/column-id.spec.ts | 6 +- .../composite-blocktype-definition.spec.ts | 6 +- .../expression-constraint-definition.spec.ts | 6 +- .../validation/checks/jayvee-model.spec.ts | 6 +- .../validation/checks/pipe-definition.spec.ts | 6 +- .../lib/validation/checks/pipe-definition.ts | 13 +- .../checks/pipeline-definition.spec.ts | 6 +- .../checks/property-assignment.spec.ts | 13 +- .../validation/checks/property-body.spec.ts | 6 +- .../lib/validation/checks/property-body.ts | 11 +- .../validation/checks/range-literal.spec.ts | 6 +- .../validation/checks/regex-literal.spec.ts | 6 +- .../validation/checks/transform-body.spec.ts | 6 +- .../transform-output-assignment.spec.ts | 6 +- .../typed-constraint-definition.spec.ts | 6 +- .../checks/valuetype-definition.spec.ts | 6 +- .../checks/valuetype-reference.spec.ts | 6 +- .../lib/validation/validation-utils.spec.ts | 6 +- libs/language-server/src/stdlib/blocktypes.jv | 406 ++++++++++++++++++ .../src/test/extension/extension.ts | 51 --- .../src/test/extension/index.ts | 5 - .../src/test/extension/lib/index.ts | 5 - .../extension/lib/test-property-meta-inf.ts | 72 ---- libs/language-server/src/test/index.ts | 1 - libs/language-server/src/test/utils.ts | 21 +- 41 files changed, 559 insertions(+), 376 deletions(-) create mode 100644 libs/language-server/src/stdlib/blocktypes.jv delete mode 100644 libs/language-server/src/test/extension/extension.ts delete mode 100644 libs/language-server/src/test/extension/index.ts delete mode 100644 libs/language-server/src/test/extension/lib/index.ts delete mode 100644 libs/language-server/src/test/extension/lib/test-property-meta-inf.ts diff --git a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts index 4561ec8e2..45351bcbe 100644 --- a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts +++ b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts @@ -3,6 +3,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { + BlockMetaInformation, BuiltinConstrainttypeDefinition, EvaluationContext, MetaInformation, @@ -10,7 +11,6 @@ import { ReferenceableBlocktypeDefinition, RuntimeParameterLiteral, ValidationContext, - getBlockMetaInf, getConstraintMetaInf, isBuiltinConstrainttypeDefinition, isReferenceableBlocktypeDefinition, @@ -81,7 +81,10 @@ function checkRuntimeParameterValueParsing( let metaInf: MetaInformation | undefined; if (isReferenceableBlocktypeDefinition(type.ref)) { - metaInf = getBlockMetaInf(type.ref); + if (!BlockMetaInformation.canBeWrapped(type.ref)) { + return; // TODO: is this the rigth thing to do here? + } + metaInf = new BlockMetaInformation(type.ref); } else if (isBuiltinConstrainttypeDefinition(type.ref)) { metaInf = getConstraintMetaInf(type.ref); } diff --git a/libs/language-server/src/lib/ast/model-util.ts b/libs/language-server/src/lib/ast/model-util.ts index 57b1c204f..f525044d8 100644 --- a/libs/language-server/src/lib/ast/model-util.ts +++ b/libs/language-server/src/lib/ast/model-util.ts @@ -7,7 +7,7 @@ import { strict as assert } from 'assert'; import { AstNode, Reference, assertUnreachable } from 'langium'; // eslint-disable-next-line import/no-cycle -import { getBlockMetaInf } from '../meta-information/meta-inf-registry'; +import { BlockMetaInformation } from '../meta-information'; import { BinaryExpression, @@ -29,7 +29,7 @@ export function collectStartingBlocks( .map((blockRef: Reference | undefined) => { if ( blockRef?.ref !== undefined && - getBlockMetaInf(blockRef.ref.type) !== undefined + BlockMetaInformation.canBeWrapped(blockRef.ref.type) ) { return blockRef.ref; } @@ -45,10 +45,10 @@ export function collectStartingBlocks( // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition const blocks = container?.blocks ?? []; for (const block of blocks) { - const blockMetaInf = getBlockMetaInf(block.type); - if (blockMetaInf === undefined) { + if (!BlockMetaInformation.canBeWrapped(block.type)) { continue; } + const blockMetaInf = new BlockMetaInformation(block.type); if (!blockMetaInf.hasInput()) { result.push(block); diff --git a/libs/language-server/src/lib/ast/value-definition.spec.ts b/libs/language-server/src/lib/ast/value-definition.spec.ts index c7095de42..781abb0f7 100644 --- a/libs/language-server/src/lib/ast/value-definition.spec.ts +++ b/libs/language-server/src/lib/ast/value-definition.spec.ts @@ -5,8 +5,6 @@ import { AstNode, LangiumDocument } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { useExtension } from '..'; -import { TestLangExtension } from '../../test/extension'; import { ParseHelperOptions, parseHelper } from '../../test/langium-utils'; import { readJvTestAssetHelper } from '../../test/utils'; import { createJayveeServices } from '../jayvee-module'; @@ -23,7 +21,7 @@ describe('Parsing of ValuetypeDefinition', () => { ); beforeAll(() => { - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension const services = createJayveeServices(NodeFileSystem).Jayvee; parse = parseHelper(services); }); diff --git a/libs/language-server/src/lib/builtin-library/stdlib.ts b/libs/language-server/src/lib/builtin-library/stdlib.ts index c1032b739..d0a7efc55 100644 --- a/libs/language-server/src/lib/builtin-library/stdlib.ts +++ b/libs/language-server/src/lib/builtin-library/stdlib.ts @@ -5,9 +5,7 @@ import { IOType, PrimitiveValuetype, internalValueToString } from '../ast'; import { PrimitiveValuetypes } from '../ast/wrappers/value-type/primitive/primitive-valuetypes'; import { - BlockMetaInformation, ConstraintMetaInformation, - blockMetaInfRegistry, constraintMetaInfRegistry, } from '../meta-information'; @@ -35,16 +33,6 @@ export const IOtypesLib = { .join('\n\n'), }; -// Is a method since metaInformationRegistry might not be initialized when this as variable. -export function getBuiltinBlocktypesLib() { - const builtins = blockMetaInfRegistry.getAllEntries(); - return { - 'builtin:///stdlib/builtin-blocktypes.jv': builtins - .map((entry) => parseBlockMetaInfToJayvee(entry.key, entry.value)) - .join('\n\n'), - }; -} - // Is a method since metaInformationRegistry might not be initialized when this as variable. export function getBuiltinConstrainttypesLib() { const builtins = constraintMetaInfRegistry.getAllEntries(); @@ -60,56 +48,10 @@ export function getStdLib() { ...PartialStdLib, ...getBuiltinValuetypesLib(), ...IOtypesLib, - ...getBuiltinBlocktypesLib(), ...getBuiltinConstrainttypesLib(), }; } -function parseBlockMetaInfToJayvee( - name: string, - metaInf: BlockMetaInformation, -): string { - const lines: string[] = []; - if (metaInf.docs.description !== undefined) { - lines.push(parseAsComment(metaInf.docs.description)); - } - if (metaInf.docs.examples !== undefined) { - metaInf.docs.examples.forEach((example, i) => { - lines.push('//'); - lines.push(`// Example ${i + 1}: ${example.description}`); - lines.push(parseAsComment(example.code)); - }); - } - - lines.push(`builtin blocktype ${name} {`); - lines.push(parseBuiltinBlocktypeBody(metaInf)); - lines.push('}'); - - return lines.join('\n'); -} - -function parseBuiltinBlocktypeBody(metaInf: BlockMetaInformation): string { - const bodyLines: string[] = []; - - bodyLines.push(`\tinput default oftype ${metaInf.inputType};`); - bodyLines.push(`\toutput default oftype ${metaInf.outputType};`); - bodyLines.push('\t'); - - Object.entries(metaInf.getPropertySpecifications()).forEach( - ([propName, propSpecification]) => { - const propDoc = propSpecification.docs?.description; - if (propDoc !== undefined) { - bodyLines.push(parseAsComment(propDoc, 1)); - } - bodyLines.push( - `\tproperty ${propName} oftype ${propSpecification.type.getName()};`, - ); - }, - ); - - return bodyLines.join('\n'); -} - function parseBuiltinValuetypeToJayvee(valuetype: PrimitiveValuetype): string { const lines: string[] = []; diff --git a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts index 681393384..a6851c17a 100644 --- a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts +++ b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts @@ -32,9 +32,9 @@ import { isReferenceableBlocktypeDefinition, } from '../ast/generated/ast'; import { LspDocGenerator } from '../docs/lsp-doc-generator'; +import { BlockMetaInformation } from '../meta-information'; import { MetaInformation } from '../meta-information/meta-inf'; import { - getBlockMetaInf, getConstraintMetaInf, getRegisteredBlockMetaInformation, getRegisteredConstraintMetaInformation, @@ -157,7 +157,10 @@ export class JayveeCompletionProvider extends DefaultCompletionProvider { let metaInf: MetaInformation | undefined; if (isReferenceableBlocktypeDefinition(container.type.ref)) { - metaInf = getBlockMetaInf(container.type.ref); + if (!BlockMetaInformation.canBeWrapped(container.type.ref)) { + return; + } + metaInf = new BlockMetaInformation(container.type.ref); } else if (isBuiltinConstrainttypeDefinition(container.type.ref)) { metaInf = getConstraintMetaInf(container.type.ref); } diff --git a/libs/language-server/src/lib/constraint/length-constraint-meta-inf.spec.ts b/libs/language-server/src/lib/constraint/length-constraint-meta-inf.spec.ts index 14fdeba5e..54c513114 100644 --- a/libs/language-server/src/lib/constraint/length-constraint-meta-inf.spec.ts +++ b/libs/language-server/src/lib/constraint/length-constraint-meta-inf.spec.ts @@ -12,9 +12,7 @@ import { TypedConstraintDefinition, ValidationContext, createJayveeServices, - useExtension, } from '../..'; -import { TestLangExtension } from '../../test/extension'; import { ParseHelperOptions, parseHelper } from '../../test/langium-utils'; import { expectNoParserAndLexerErrors, @@ -54,8 +52,8 @@ describe('Validation of LengthConstraint', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/constraint/meta-inf-example-validation.spec.ts b/libs/language-server/src/lib/constraint/meta-inf-example-validation.spec.ts index 57c2859e7..b7e2f2834 100644 --- a/libs/language-server/src/lib/constraint/meta-inf-example-validation.spec.ts +++ b/libs/language-server/src/lib/constraint/meta-inf-example-validation.spec.ts @@ -5,9 +5,7 @@ import { AstNode } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { TestLangExtension } from '../../test/extension'; import { ValidationResult, validationHelper } from '../../test/langium-utils'; -import { useExtension } from '../extension'; import { JayveeServices, createJayveeServices } from '../jayvee-module'; import { getAvailableConstraintMetaInf } from './constraint-registry'; @@ -17,8 +15,8 @@ describe('Validation of builtin examples of ConstraintMetaInformation', () => { let validate: (input: string) => Promise>; beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services services = createJayveeServices(NodeFileSystem).Jayvee; // Create validation helper for language services diff --git a/libs/language-server/src/lib/constraint/range-constraint-meta-inf.spec.ts b/libs/language-server/src/lib/constraint/range-constraint-meta-inf.spec.ts index d2cbbb309..0a84895c9 100644 --- a/libs/language-server/src/lib/constraint/range-constraint-meta-inf.spec.ts +++ b/libs/language-server/src/lib/constraint/range-constraint-meta-inf.spec.ts @@ -12,9 +12,7 @@ import { TypedConstraintDefinition, ValidationContext, createJayveeServices, - useExtension, } from '../..'; -import { TestLangExtension } from '../../test/extension'; import { ParseHelperOptions, parseHelper } from '../../test/langium-utils'; import { expectNoParserAndLexerErrors, @@ -54,8 +52,8 @@ describe('Validation of RangeConstraint', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/hover/jayvee-hover-provider.ts b/libs/language-server/src/lib/hover/jayvee-hover-provider.ts index 4dc9f07ee..cb6e83582 100644 --- a/libs/language-server/src/lib/hover/jayvee-hover-provider.ts +++ b/libs/language-server/src/lib/hover/jayvee-hover-provider.ts @@ -22,8 +22,8 @@ import { } from '../ast'; import { LspDocGenerator } from '../docs/lsp-doc-generator'; import { + BlockMetaInformation, MetaInformation, - getBlockMetaInf, getConstraintMetaInf, } from '../meta-information'; @@ -57,10 +57,10 @@ export class JayveeHoverProvider extends AstNodeHoverProvider { private getBlockTypeMarkdownDoc( blockType: BuiltinBlocktypeDefinition, ): string | undefined { - const blockMetaInf = getBlockMetaInf(blockType); - if (blockMetaInf === undefined) { + if (!BlockMetaInformation.canBeWrapped(blockType)) { return; } + const blockMetaInf = new BlockMetaInformation(blockType); const lspDocBuilder = new LspDocGenerator(); return lspDocBuilder.generateBlockTypeDoc(blockMetaInf); @@ -81,14 +81,17 @@ export class JayveeHoverProvider extends AstNodeHoverProvider { private getPropertyMarkdownDoc( property: PropertyAssignment, ): string | undefined { - const block = property.$container.$container; + const container = property.$container.$container; let metaInf: MetaInformation | undefined; - if (isTypedConstraintDefinition(block)) { - metaInf = getConstraintMetaInf(block.type); - } else if (isBlockDefinition(block)) { - metaInf = getBlockMetaInf(block.type); + if (isTypedConstraintDefinition(container)) { + metaInf = getConstraintMetaInf(container.type); + } else if (isBlockDefinition(container)) { + if (!BlockMetaInformation.canBeWrapped(container.type)) { + return; + } + metaInf = new BlockMetaInformation(container.type); } else { - assertUnreachable(block); + assertUnreachable(container); } if (metaInf === undefined) { return; diff --git a/libs/language-server/src/lib/index.ts b/libs/language-server/src/lib/index.ts index 5e405c318..e8a5c1792 100644 --- a/libs/language-server/src/lib/index.ts +++ b/libs/language-server/src/lib/index.ts @@ -12,4 +12,3 @@ export * from './util'; export * from './validation'; export * from './jayvee-module'; -export * from './extension'; diff --git a/libs/language-server/src/lib/meta-information/block-meta-inf.ts b/libs/language-server/src/lib/meta-information/block-meta-inf.ts index 699b45ebb..49af60541 100644 --- a/libs/language-server/src/lib/meta-information/block-meta-inf.ts +++ b/libs/language-server/src/lib/meta-information/block-meta-inf.ts @@ -2,11 +2,16 @@ // // SPDX-License-Identifier: AGPL-3.0-only +import { strict as assert } from 'assert'; + +import { Reference, isReference } from 'langium'; + // eslint-disable-next-line import/no-cycle -import { IOType } from '../ast'; -import { EvaluationContext } from '../ast/expressions/evaluation'; -import { PropertyBody } from '../ast/generated/ast'; -import { ValidationContext } from '../validation/validation-context'; +import { IOType, createValuetype, getIOType } from '../ast'; +import { + ReferenceableBlocktypeDefinition, + isBuiltinBlocktypeDefinition, +} from '../ast/generated/ast'; import { ExampleDoc, MetaInformation, PropertySpecification } from './meta-inf'; @@ -15,21 +20,59 @@ interface BlockDocs { examples?: ExampleDoc[]; } -export abstract class BlockMetaInformation extends MetaInformation { +export class BlockMetaInformation extends MetaInformation { docs: BlockDocs = {}; - protected constructor( - blockType: string, - properties: Record, - public readonly inputType: IOType, - public readonly outputType: IOType, - validation?: ( - property: PropertyBody, - validationContext: ValidationContext, - evaluationContext: EvaluationContext, - ) => void, + readonly inputType: IOType; + readonly outputType: IOType; + + constructor( + toBeWrapped: + | ReferenceableBlocktypeDefinition + | Reference, ) { - super(blockType, properties, validation); + const blocktypeDefinition = isReference(toBeWrapped) + ? toBeWrapped.ref + : toBeWrapped; + assert(blocktypeDefinition !== undefined); + + const blocktypeName = blocktypeDefinition.name; + + const properties: Record = {}; + for (const property of blocktypeDefinition.properties) { + const valuetype = createValuetype(property.valueType); + assert(valuetype !== undefined); + + properties[property.name] = { + type: valuetype, + }; + } + + super(blocktypeName, properties, undefined); + + const inputPort = blocktypeDefinition.inputs[0]; + assert(inputPort !== undefined); + this.inputType = getIOType(inputPort); + + const outputPort = blocktypeDefinition.outputs[0]; + assert(outputPort !== undefined); + this.outputType = getIOType(outputPort); + } + + static canBeWrapped( + toBeWrapped: + | ReferenceableBlocktypeDefinition + | Reference, + ): boolean { + const blocktypeDefinition = isReference(toBeWrapped) + ? toBeWrapped.ref + : toBeWrapped; + + // TODO: implement + if (isBuiltinBlocktypeDefinition(blocktypeDefinition)) { + return true; + } + return true; } canBeConnectedTo(blockAfter: BlockMetaInformation): boolean { diff --git a/libs/language-server/src/lib/meta-information/composite-blocktype-meta-inf.ts b/libs/language-server/src/lib/meta-information/composite-blocktype-meta-inf.ts index 6d17bc6a2..3b7083396 100644 --- a/libs/language-server/src/lib/meta-information/composite-blocktype-meta-inf.ts +++ b/libs/language-server/src/lib/meta-information/composite-blocktype-meta-inf.ts @@ -2,39 +2,14 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { strict as assert } from 'assert'; - // eslint-disable-next-line import/no-cycle -import { - BlocktypeInput, - BlocktypeOutput, - CompositeBlocktypeDefinition, - createValuetype, - getIOType, -} from '../ast'; +import { CompositeBlocktypeDefinition } from '../ast'; import { BlockMetaInformation } from './block-meta-inf'; -import { PropertySpecification } from './meta-inf'; export class CompositeBlocktypeMetaInformation extends BlockMetaInformation { constructor(private blockTypeDefinition: CompositeBlocktypeDefinition) { - const properties: Record = {}; - - for (const property of blockTypeDefinition.properties) { - const valuetype = createValuetype(property.valueType); - assert(valuetype !== undefined); - - properties[property.name] = { - type: valuetype, - }; - } - - super( - blockTypeDefinition.name, - properties, - getIOType(blockTypeDefinition.inputs[0] as BlocktypeInput), - getIOType(blockTypeDefinition.outputs[0] as BlocktypeOutput), - ); + super(blockTypeDefinition); } override getMissingRequiredPropertyNames( diff --git a/libs/language-server/src/lib/meta-information/index.ts b/libs/language-server/src/lib/meta-information/index.ts index 60a9ca4af..9f35ece74 100644 --- a/libs/language-server/src/lib/meta-information/index.ts +++ b/libs/language-server/src/lib/meta-information/index.ts @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only +// eslint-disable-next-line import/no-cycle export * from './block-meta-inf'; export * from './constraint-meta-inf'; export * from './meta-inf'; diff --git a/libs/language-server/src/lib/validation/checks/block-definition.spec.ts b/libs/language-server/src/lib/validation/checks/block-definition.spec.ts index 7c8d1aecd..e6411cbee 100644 --- a/libs/language-server/src/lib/validation/checks/block-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/block-definition.spec.ts @@ -9,7 +9,6 @@ import { BlockDefinition, ValidationContext, createJayveeServices, - useExtension, } from '../..'; import { ParseHelperOptions, @@ -18,7 +17,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateBlockDefinition } from './block-definition'; @@ -53,8 +51,8 @@ describe('Validation of BlockDefinition', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/block-definition.ts b/libs/language-server/src/lib/validation/checks/block-definition.ts index 52d05bd8a..21de9d67c 100644 --- a/libs/language-server/src/lib/validation/checks/block-definition.ts +++ b/libs/language-server/src/lib/validation/checks/block-definition.ts @@ -18,7 +18,7 @@ import { collectOutgoingPipes, } from '../../ast/model-util'; import { PipeWrapper } from '../../ast/wrappers/pipe-wrapper'; -import { getBlockMetaInf } from '../../meta-information/meta-inf-registry'; +import { BlockMetaInformation } from '../../meta-information'; import { ValidationContext } from '../validation-context'; export function validateBlockDefinition( @@ -34,10 +34,10 @@ function checkPipesOfBlock( whatToCheck: 'input' | 'output', context: ValidationContext, ): void { - const blockMetaInf = getBlockMetaInf(block?.type); - if (blockMetaInf === undefined) { + if (!BlockMetaInformation.canBeWrapped(block?.type)) { return; } + const blockMetaInf = new BlockMetaInformation(block?.type); let pipes: PipeWrapper[]; switch (whatToCheck) { diff --git a/libs/language-server/src/lib/validation/checks/blocktype-definition.spec.ts b/libs/language-server/src/lib/validation/checks/blocktype-definition.spec.ts index 7fa5ef44e..de1f530b6 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-definition.spec.ts @@ -11,7 +11,6 @@ import { RuntimeParameterProvider, ValidationContext, createJayveeServices, - useExtension, } from '../..'; import { ParseHelperOptions, @@ -20,7 +19,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateBlocktypeDefinition } from './blocktype-definition'; @@ -56,8 +54,8 @@ describe('Validation of BuiltinBlocktypeDefinition', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/column-id.spec.ts b/libs/language-server/src/lib/validation/checks/column-id.spec.ts index a9d7b902b..4742dd29f 100644 --- a/libs/language-server/src/lib/validation/checks/column-id.spec.ts +++ b/libs/language-server/src/lib/validation/checks/column-id.spec.ts @@ -9,7 +9,6 @@ import { ColumnId, ValidationContext, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -18,7 +17,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateColumnId } from './column-id'; @@ -50,8 +48,8 @@ describe('Validation of ColumnId', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts b/libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts index e30fd3bf5..26aa57d27 100644 --- a/libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts @@ -11,7 +11,6 @@ import { RuntimeParameterProvider, ValidationContext, createJayveeServices, - useExtension, } from '../..'; import { ParseHelperOptions, @@ -20,7 +19,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateCompositeBlockTypeDefinition } from './composite-blocktype-definition'; @@ -56,8 +54,8 @@ describe('Validation of CompositeBlocktypeDefinition', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/expression-constraint-definition.spec.ts b/libs/language-server/src/lib/validation/checks/expression-constraint-definition.spec.ts index 1df72d359..7047b7ee8 100644 --- a/libs/language-server/src/lib/validation/checks/expression-constraint-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/expression-constraint-definition.spec.ts @@ -11,7 +11,6 @@ import { RuntimeParameterProvider, ValidationContext, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -20,7 +19,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateExpressionConstraintDefinition } from './expression-constraint-definition'; @@ -57,8 +55,8 @@ describe('Validation of ConstraintDefinition (expression syntax)', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/jayvee-model.spec.ts b/libs/language-server/src/lib/validation/checks/jayvee-model.spec.ts index 4a5a034fd..8668c5945 100644 --- a/libs/language-server/src/lib/validation/checks/jayvee-model.spec.ts +++ b/libs/language-server/src/lib/validation/checks/jayvee-model.spec.ts @@ -9,7 +9,6 @@ import { JayveeModel, ValidationContext, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -18,7 +17,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateJayveeModel } from './jayvee-model'; @@ -48,8 +46,8 @@ describe('Validation of JayveeModel', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; // Parse function for Jayvee (without validation) diff --git a/libs/language-server/src/lib/validation/checks/pipe-definition.spec.ts b/libs/language-server/src/lib/validation/checks/pipe-definition.spec.ts index c28e23483..8620efa50 100644 --- a/libs/language-server/src/lib/validation/checks/pipe-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/pipe-definition.spec.ts @@ -9,7 +9,6 @@ import { PipeDefinition, ValidationContext, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -18,7 +17,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validatePipeDefinition } from './pipe-definition'; @@ -50,8 +48,8 @@ describe('Validation of PipeDefinition', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/pipe-definition.ts b/libs/language-server/src/lib/validation/checks/pipe-definition.ts index 523563813..93234dec0 100644 --- a/libs/language-server/src/lib/validation/checks/pipe-definition.ts +++ b/libs/language-server/src/lib/validation/checks/pipe-definition.ts @@ -9,7 +9,7 @@ import { PipeDefinition } from '../../ast/generated/ast'; import { createSemanticPipes } from '../../ast/wrappers/pipe-wrapper'; -import { getBlockMetaInf } from '../../meta-information/meta-inf-registry'; +import { BlockMetaInformation } from '../../meta-information'; import { ValidationContext } from '../validation-context'; export function validatePipeDefinition( @@ -28,13 +28,14 @@ function checkBlockCompatibility( const fromBlockType = semanticPipe.from?.type; const toBlockType = semanticPipe.to?.type; - const fromBlockMetaInf = getBlockMetaInf(fromBlockType); - - const toBlockMetaInf = getBlockMetaInf(toBlockType); - - if (fromBlockMetaInf === undefined || toBlockMetaInf === undefined) { + if ( + !BlockMetaInformation.canBeWrapped(fromBlockType) || + !BlockMetaInformation.canBeWrapped(toBlockType) + ) { continue; } + const fromBlockMetaInf = new BlockMetaInformation(fromBlockType); + const toBlockMetaInf = new BlockMetaInformation(toBlockType); if (fromBlockMetaInf.hasOutput() && toBlockMetaInf.hasInput()) { if (!fromBlockMetaInf.canBeConnectedTo(toBlockMetaInf)) { diff --git a/libs/language-server/src/lib/validation/checks/pipeline-definition.spec.ts b/libs/language-server/src/lib/validation/checks/pipeline-definition.spec.ts index 80876768d..fb4d19527 100644 --- a/libs/language-server/src/lib/validation/checks/pipeline-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/pipeline-definition.spec.ts @@ -9,7 +9,6 @@ import { PipelineDefinition, ValidationContext, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -18,7 +17,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validatePipelineDefinition } from './pipeline-definition'; @@ -53,8 +51,8 @@ describe('Validation of PipelineDefinition', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index b17b2fd22..8d5110e66 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -6,6 +6,7 @@ import { AstNode, AstNodeLocator, LangiumDocument } from 'langium'; import { NodeFileSystem } from 'langium/node'; import { + BlockMetaInformation, EvaluationContext, MetaInformation, PropertyAssignment, @@ -13,11 +14,9 @@ import { RuntimeParameterProvider, ValidationContext, createJayveeServices, - getBlockMetaInf, getConstraintMetaInf, isBuiltinConstrainttypeDefinition, isReferenceableBlocktypeDefinition, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -26,7 +25,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validatePropertyAssignment } from './property-assignment'; @@ -57,7 +55,10 @@ describe('Validation of PropertyAssignment', () => { const type = propertyBody.$container.type; let metaInf: MetaInformation | undefined; if (isReferenceableBlocktypeDefinition(type.ref)) { - metaInf = getBlockMetaInf(type.ref); + if (!BlockMetaInformation.canBeWrapped(type.ref)) { + return; // TODO: is this the right to do here? + } + metaInf = new BlockMetaInformation(type.ref); } else if (isBuiltinConstrainttypeDefinition(type.ref)) { metaInf = getConstraintMetaInf(type.ref); } @@ -77,8 +78,8 @@ describe('Validation of PropertyAssignment', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/property-body.spec.ts b/libs/language-server/src/lib/validation/checks/property-body.spec.ts index f19f4a133..311fe60b6 100644 --- a/libs/language-server/src/lib/validation/checks/property-body.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-body.spec.ts @@ -11,7 +11,6 @@ import { RuntimeParameterProvider, ValidationContext, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -20,7 +19,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validatePropertyBody } from './property-body'; @@ -56,8 +54,8 @@ describe('Validation PropertyBody', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/property-body.ts b/libs/language-server/src/lib/validation/checks/property-body.ts index 1db600192..f2829057b 100644 --- a/libs/language-server/src/lib/validation/checks/property-body.ts +++ b/libs/language-server/src/lib/validation/checks/property-body.ts @@ -16,11 +16,9 @@ import { isBuiltinConstrainttypeDefinition, isReferenceableBlocktypeDefinition, } from '../../ast/generated/ast'; +import { BlockMetaInformation } from '../../meta-information/block-meta-inf'; import { MetaInformation } from '../../meta-information/meta-inf'; -import { - getBlockMetaInf, - getConstraintMetaInf, -} from '../../meta-information/meta-inf-registry'; +import { getConstraintMetaInf } from '../../meta-information/meta-inf-registry'; import { ValidationContext } from '../validation-context'; import { checkUniqueNames } from '../validation-util'; @@ -76,7 +74,10 @@ function inferMetaInformation( if (isBuiltinConstrainttypeDefinition(type)) { return getConstraintMetaInf(type); } else if (isReferenceableBlocktypeDefinition(type)) { - return getBlockMetaInf(type); + if (!BlockMetaInformation.canBeWrapped(type)) { + return; + } + return new BlockMetaInformation(type); } assertUnreachable(type); diff --git a/libs/language-server/src/lib/validation/checks/range-literal.spec.ts b/libs/language-server/src/lib/validation/checks/range-literal.spec.ts index 87f6b3cb7..ffa8e24b9 100644 --- a/libs/language-server/src/lib/validation/checks/range-literal.spec.ts +++ b/libs/language-server/src/lib/validation/checks/range-literal.spec.ts @@ -9,7 +9,6 @@ import { RangeLiteral, ValidationContext, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -18,7 +17,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateRangeLiteral } from './range-literal'; @@ -53,8 +51,8 @@ describe('Validation of RangeLiteral', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/regex-literal.spec.ts b/libs/language-server/src/lib/validation/checks/regex-literal.spec.ts index 0778a496e..79c0edc6c 100644 --- a/libs/language-server/src/lib/validation/checks/regex-literal.spec.ts +++ b/libs/language-server/src/lib/validation/checks/regex-literal.spec.ts @@ -9,7 +9,6 @@ import { RegexLiteral, ValidationContext, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -18,7 +17,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateRegexLiteral } from './regex-literal'; @@ -53,8 +51,8 @@ describe('Validation of RegexLiteral', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/transform-body.spec.ts b/libs/language-server/src/lib/validation/checks/transform-body.spec.ts index 4d66c8e73..55492693e 100644 --- a/libs/language-server/src/lib/validation/checks/transform-body.spec.ts +++ b/libs/language-server/src/lib/validation/checks/transform-body.spec.ts @@ -11,7 +11,6 @@ import { TransformBody, ValidationContext, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -20,7 +19,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateTransformBody } from './transform-body'; @@ -56,8 +54,8 @@ describe('Validation of TransformBody', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/transform-output-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/transform-output-assignment.spec.ts index 499710322..f8f2d7d32 100644 --- a/libs/language-server/src/lib/validation/checks/transform-output-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/transform-output-assignment.spec.ts @@ -11,7 +11,6 @@ import { TransformOutputAssignment, ValidationContext, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -20,7 +19,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateTransformOutputAssignment } from './transform-output-assigment'; @@ -57,8 +55,8 @@ describe('Validation of TransformOutputAssignment', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/typed-constraint-definition.spec.ts b/libs/language-server/src/lib/validation/checks/typed-constraint-definition.spec.ts index 305e1819f..10cf8c8ff 100644 --- a/libs/language-server/src/lib/validation/checks/typed-constraint-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/typed-constraint-definition.spec.ts @@ -9,7 +9,6 @@ import { TypedConstraintDefinition, ValidationContext, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -18,7 +17,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateTypedConstraintDefinition } from './typed-constraint-definition'; @@ -53,8 +51,8 @@ describe('Validation of ConstraintDefinition (typed syntax)', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/valuetype-definition.spec.ts b/libs/language-server/src/lib/validation/checks/valuetype-definition.spec.ts index 3dceb071e..9cb974f37 100644 --- a/libs/language-server/src/lib/validation/checks/valuetype-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/valuetype-definition.spec.ts @@ -11,7 +11,6 @@ import { ValidationContext, ValuetypeDefinition, createJayveeServices, - useExtension, } from '../../../lib'; import { ParseHelperOptions, @@ -20,7 +19,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateValuetypeDefinition } from './valuetype-definition'; @@ -56,8 +54,8 @@ describe('Validation of ValuetypeDefinition', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/valuetype-reference.spec.ts b/libs/language-server/src/lib/validation/checks/valuetype-reference.spec.ts index 76ccc6b38..b04faa9cc 100644 --- a/libs/language-server/src/lib/validation/checks/valuetype-reference.spec.ts +++ b/libs/language-server/src/lib/validation/checks/valuetype-reference.spec.ts @@ -12,7 +12,6 @@ import { ValuetypeDefinition, ValuetypeReference, createJayveeServices, - useExtension, } from '../..'; import { ParseHelperOptions, @@ -21,7 +20,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../../test'; -import { TestLangExtension } from '../../../test/extension'; import { validateValuetypeReference } from './valuetype-reference'; @@ -65,8 +63,8 @@ describe('Validation of ValuetypeReference', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/validation-utils.spec.ts b/libs/language-server/src/lib/validation/validation-utils.spec.ts index d00584c47..9b5087967 100644 --- a/libs/language-server/src/lib/validation/validation-utils.spec.ts +++ b/libs/language-server/src/lib/validation/validation-utils.spec.ts @@ -10,7 +10,6 @@ import { ValidationContext, checkUniqueNames, createJayveeServices, - useExtension, } from '..'; import { ParseHelperOptions, @@ -19,7 +18,6 @@ import { readJvTestAssetHelper, validationAcceptorMockImpl, } from '../../test'; -import { TestLangExtension } from '../../test/extension'; describe('Validation of validation-utils', () => { let parse: ( @@ -47,8 +45,8 @@ describe('Validation of validation-utils', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + // TODO: fix tests after removing TestExtension + // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/stdlib/blocktypes.jv b/libs/language-server/src/stdlib/blocktypes.jv new file mode 100644 index 000000000..977a2111b --- /dev/null +++ b/libs/language-server/src/stdlib/blocktypes.jv @@ -0,0 +1,406 @@ +/* +Deletes columns from a `Sheet`. Column IDs of subsequent columns will be shifted accordingly, so there will be no gaps. + +@example Deletes column B (i.e. the second column). +block MpgColumnDeleter oftype ColumnDeleter { + delete: [column B]; +} +*/ +builtin blocktype ColumnDeleter { + input default oftype Sheet; + output default oftype Sheet; + + // The columns to delete. + property delete oftype Collection; +} + +/* +Deletes one or more rows from a `Sheet`. Row IDs of subsequent rows will be shifted accordingly, so there will be no gaps. + +@example Deletes row 2 (i.e. the second row). +block SecondRowDeleter oftype RowDeleter { + delete: [row 2]; +} +*/ +builtin blocktype RowDeleter { + input default oftype Sheet; + output default oftype Sheet; + + // The rows to delete. + property delete oftype Collection; +} + +/* +Selects a subset of a `Sheet` to produce a new `Sheet`. + +@example Selects the cells in the given range and produces a new `Sheet` containing only the selected cells. +block CarsCoreDataSelector oftype CellRangeSelector { + select: range A1:E*; +} +*/ +builtin blocktype CellRangeSelector { + input default oftype Sheet; + output default oftype Sheet; + + // The cell range to select. + property select oftype CellRange; +} + +/* +Writes textual values into cells of a `Sheet`. The number of text values needs to match the number of cells to write into. + +@example Write the value "Name" into cell `A1`. +block NameHeaderWriter oftype CellWriter { + at: cell A1; + write: ["Name"]; +} + +@example Write the values "Name", "Age" into cells `A1` and `A2`. +block HeaderSequenceWriter oftype CellWriter { + at: range A1:A2; + write: ["Name", "Age"]; +} +*/ +builtin blocktype CellWriter { + input default oftype Sheet; + output default oftype Sheet; + + // The values to write. + property write oftype Collection; + // The cells to write into. + property at oftype CellRange; +} + +/* +Interprets a `Sheet` as a `Table`. In case a header row is present in the sheet, its names can be matched with the provided column names. Otherwise, the provided column names are assigned in order. + +@example Interprets a `Sheet` about cars with a topmost header row and interprets it as a `Table` by assigning a primitive valuetype to each column. The column names are matched to the header, so the order of the type assignments does not matter. +block CarsTableInterpreter oftype TableInterpreter { + header: true; + columns: [ + "name" oftype text, + "mpg" oftype decimal, + "cyl" oftype integer, + ]; +} + +@example Interprets a `Sheet` about cars without a topmost header row and interprets it as a `Table` by sequentially assigning a name and a primitive valuetype to each column of the sheet. Note that the order of columns matters here. The first column (column `A`) will be named "name", the second column (column `B`) will be named "mpg" etc. +block CarsTableInterpreter oftype TableInterpreter { + header: false; + columns: [ + "name" oftype text, + "mpg" oftype decimal, + "cyl" oftype integer, + ]; +} +*/ +builtin blocktype TableInterpreter { + input default oftype Sheet; + output default oftype Table; + + // Whether the first row should be interpreted as header row. + property header oftype boolean; + // Collection of valuetype assignments. Uses column names (potentially matched with the header or by sequence depending on the `header` property) to assign a primitive valuetype to each column. + property columns oftype Collection; +} + +/* +Interprets an input file as a csv-file containing string-values delimited by `delimiter` and outputs a `Sheet`. + +@example Interprets an input file as a csv-file containing string-values delimited by `;` and outputs `Sheet`. +block AgencyCSVInterpreter oftype CSVInterpreter { + delimiter: ";"; + } +*/ +builtin blocktype CSVInterpreter { + input default oftype TextFile; + output default oftype Sheet; + + // The delimiter for values in the CSV file. + property delimiter oftype text; + // The enclosing character that may be used for values in the CSV file. + property enclosing oftype text; + // The character to escape enclosing characters in values. + property enclosingEscape oftype text; +} + +/* +Applies a transform on each value of a column. The input port type of the used transform has to match the type of the input column. + +@example Given a column "temperature" with temperature values in Celsius, it overwrites the column with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model. + +transform CelsiusToFahrenheit { + from Celsius oftype decimal; + to Fahrenheit oftype decimal; + + Fahrenheit: (Celsius * 9/5) + 32; +} + +block CelsiusToFahrenheitTransformer oftype TableTransformer { + inputColumns: ['temperature']; + outputColumn: 'temperature'; + use: CelsiusToFahrenheit; +} + +@example Given a column "temperatureCelsius" with temperature values in Celsius, it adds a new column "temperatureFahrenheit" with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model. + +transform CelsiusToFahrenheit { + from Celsius oftype decimal; + to Fahrenheit oftype decimal; + + Fahrenheit: (Celsius * 9/5) + 32; +} + +block CelsiusToFahrenheitTransformer oftype TableTransformer { + inputColumns: ['temperatureCelsius']; + outputColumn: 'temperatureFahrenheit'; + use: CelsiusToFahrenheit; +} +*/ +builtin blocktype TableTransformer { + input default oftype Table; + output default oftype Table; + + // The names of the input columns. The columns have to be present in the table and match with the transform's input port types. + property inputColumns oftype Collection; + // The name of the output column. Overwrites the column if it already exists, or otherwise creates a new one. + property outputColumn oftype text; + // Reference to the transform that is applied to the column. + property use oftype Transform; +} + +/* +Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s. + +@example Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s. +block AgencyXLSXInterpreter oftype XLSXInterpreter { + } +*/ +builtin blocktype XLSXInterpreter { + input default oftype File; + output default oftype Workbook; + +} + +/* +Selects one `Sheet` from a `Workbook` based on its `sheetName`. If no sheet matches the name, no output is created and the execution of the pipeline is aborted. + +@example Tries to pick the sheet `AgencyNames` from the provided `Workbook`. If `AgencyNames` exists it is passed on as `Sheet`, if it does not exist the execution of the pipeline is aborted. +block AgencySheetPicker oftype SheetPicker { + sheetName: "AgencyNames"; +} +*/ +builtin blocktype SheetPicker { + input default oftype Workbook; + output default oftype Sheet; + + // The name of the sheet to select. + property sheetName oftype text; +} + +/* +Loads a `Table` into a PostgreSQL database sink. + +@example A local Postgres instance is filled with table data about cars. +block CarsLoader oftype PostgresLoader { + host: "localhost"; + port: 5432; + username: "postgres"; + password: "postgres"; + database: "CarsDB"; + table: "Cars"; +} +*/ +builtin blocktype PostgresLoader { + input default oftype Table; + output default oftype None; + + // The hostname or IP address of the Postgres database. + property host oftype text; + // The port of the Postgres database. + property port oftype integer; + // The username to login to the Postgres database. + property username oftype text; + // The password to login to the Postgres database. + property password oftype text; + // The database to use. + property database oftype text; + // The name of the table to write into. + property table oftype text; +} + +/* +Loads a `Table` into a SQLite database sink. + +@example A SQLite file `cars.db` is created in the working directory. Incoming data is written to the table `cars`. +block CarsLoader oftype SQLiteLoader { + table: "cars"; + file: "./cars.db"; +} +*/ +builtin blocktype SQLiteLoader { + input default oftype Table; + output default oftype None; + + // The name of the table to write into. + property table oftype text; + // The path to a SQLite file that will be created if it does not exist. Usual file extensions are `.sqlite` and `.db`. + property file oftype text; + // Indicates, whether to drop the table before loading data into it. If `false`, data is appended to the table instead of dropping it. + property dropTable oftype boolean; +} + +/* +Extracts a `File` from the web. + +@example Fetches a file from the given URL. +block CarsFileExtractor oftype HttpExtractor { + url: "tinyurl.com/4ub9spwz"; +} +*/ +builtin blocktype HttpExtractor { + input default oftype None; + output default oftype File; + + // The URL to the file in the web to extract. + property url oftype text; + // Configures how many retries should be executed after a failure fetching the data. + property retries oftype integer; + // Configures the wait time in milliseconds before executing a retry. + property retryBackoffMilliseconds oftype integer; + // Configures the wait strategy before executing a retry. Can have values "exponential" or "linear". + property retryBackoffStrategy oftype text; + // Indicates, whether to follow redirects on get requests. If `false`, redirects are not followed. Default `true` + property followRedirects oftype boolean; +} + +/* +Interprets a `File` as a `TextFile`. +*/ +builtin blocktype TextFileInterpreter { + input default oftype File; + output default oftype TextFile; + + // The encoding used for decoding the file contents. + property encoding oftype text; + // The regex for identifying line breaks. + property lineBreak oftype Regex; +} + +/* +Selects a range of lines from a `TextFile`. +*/ +builtin blocktype TextRangeSelector { + input default oftype TextFile; + output default oftype TextFile; + + property lineFrom oftype integer; + property lineTo oftype integer; +} + +/* +Deletes individual lines from a `TextFile`. +*/ +builtin blocktype TextLineDeleter { + input default oftype TextFile; + output default oftype TextFile; + + // The line numbers to delete. + property lines oftype Collection; +} + +/* +Interprets a `File` as an archive file and converts it to a `FileSystem`. The archive file root is considered the root of the `FileSystem`. + +@example Interprets a `File` as a ZIP-archive and creates a `FileSystem` of its extracted contents. +block ZipArchiveInterpreter oftype ArchiveInterpreter { + archiveType: "zip"; +} +*/ +builtin blocktype ArchiveInterpreter { + input default oftype File; + output default oftype FileSystem; + + // The archive type to be interpreted, e.g., "zip" or "gz". + property archiveType oftype text; +} + +/* +Selects one `File` from a `FileSystem` based on its relative path to the root of the `FileSystem`. If no file matches the relative path, no output is created and the execution of the pipeline is aborted. + +@example Tries to pick the file `agency.txt` from the root of the provided `FileSystem`. If `agency.txt` exists it is passed on as `File`, if it does not exist the execution of the pipeline is aborted. +block AgencyFilePicker oftype FilePicker { + path: "./agency.txt"; +} +*/ +builtin blocktype FilePicker { + input default oftype FileSystem; + output default oftype File; + + // The path of the file to select, relative to the root of the provided `FileSystem`. + property path oftype text; +} + +/* +Interprets an protobuf file (binary) of type `File` by decoding the file according to `gtfs-realtime.proto`. Outputs the extracted entity defined by `entity` as a `Sheet` + +@example A file is interpretet as an GTFS-RT file, which contains TripUpdate. +block GtfsRTTripUpdateInterpreter oftype GtfsRTInterpreter{ + entity: "trip_update"; +} +*/ +builtin blocktype GtfsRTInterpreter { + input default oftype File; + output default oftype Sheet; + + // Entity to process from GTFS-RT-feed (`trip_update`, `alert` or `vehicle`). + // We currently support following Output-Sheets, each are an equivalent to the flattened Element Index defined in (just required fields are included)): + // + // Entity TripUpdate: + // ``` + // [ + // 'header.gtfs_realtime_version', + // 'header.timestamp', + // 'header.incrementality', + // 'entity.id', + // 'entity.trip_update.trip.trip_id', + // 'entity.trip_update.trip.route_id', + // 'entity.trip_update.stop_time_update.stop_sequence', + // 'entity.trip_update.stop_time_update.stop_id', + // 'entity.trip_update.stop_time_update.arrival.time', + // 'entity.trip_update.stop_time_update.departure.time', + // ]; + // + // ``` + // Entity VehiclePosition: + // ``` + // [ + // 'header.gtfs_realtime_version', + // 'header.timestamp', + // 'header.incrementality', + // 'entity.id', + // 'entity.vehicle_position.vehicle_descriptor.id', + // 'entity.vehicle_position.trip.trip_id', + // 'entity.vehicle_position.trip.route_id', + // 'entity.vehicle_position.position.latitude', + // 'entity.vehicle_position.position.longitude', + // 'entity.vehicle_position.timestamp', + // ]; + // ``` + // + // Entity Alert: + // ``` + // [ + // 'header.gtfs_realtime_version', + // 'header.timestamp', + // 'header.incrementality', + // 'entity.id', + // 'entity.alert.informed_entity.route_id', + // 'entity.alert.header_text', + // 'entity.alert.description_text', + // ]; + // ``` + // + // + property entity oftype text; +} \ No newline at end of file diff --git a/libs/language-server/src/test/extension/extension.ts b/libs/language-server/src/test/extension/extension.ts deleted file mode 100644 index 705b04303..000000000 --- a/libs/language-server/src/test/extension/extension.ts +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - ConstructorClass, - IOType, - JayveeLangExtension, -} from '../../lib'; - -import { TestPropertyMetaInformation } from './lib'; - -export class TestLangExtension implements JayveeLangExtension { - getBlockMetaInf(): Array> { - const ioTypes = Object.values(IOType); - return [ - TestPropertyMetaInformation, - ...ioTypes.map((ioType) => - this.constructBlockMetaInformationFromIOType(ioType, 'input'), - ), - ...ioTypes.map((ioType) => - this.constructBlockMetaInformationFromIOType(ioType, 'output'), - ), - ]; - } - - /** - * Constructs BlockMetaInformation that is either an loader or extractor block, depending on the io param. - * The name of the new Block is constructed `Test${ioType}${io === 'input' ? 'Loader' : 'Extractor'}`. - * For example if ioType = IOType.File and io = 'input' -> 'TestFileLoader' - * @param ioType IOType of the block input or output (depending on io param) - * @param io specifies whether the given ioType param is the input or output of the block - * @returns ConstructorClass - */ - constructBlockMetaInformationFromIOType( - ioType: IOType, - io: 'input' | 'output', - ): ConstructorClass { - return class TestBlockMetaInformation extends BlockMetaInformation { - constructor() { - super( - `Test${ioType}${io === 'input' ? 'Loader' : 'Extractor'}`, - {}, - io === 'input' ? ioType : IOType.NONE, - io === 'input' ? IOType.NONE : ioType, - ); - } - }; - } -} diff --git a/libs/language-server/src/test/extension/index.ts b/libs/language-server/src/test/extension/index.ts deleted file mode 100644 index 88d3a0045..000000000 --- a/libs/language-server/src/test/extension/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -export * from './extension'; diff --git a/libs/language-server/src/test/extension/lib/index.ts b/libs/language-server/src/test/extension/lib/index.ts deleted file mode 100644 index 49a688fd8..000000000 --- a/libs/language-server/src/test/extension/lib/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -export * from './test-property-meta-inf'; diff --git a/libs/language-server/src/test/extension/lib/test-property-meta-inf.ts b/libs/language-server/src/test/extension/lib/test-property-meta-inf.ts deleted file mode 100644 index 792e0bdee..000000000 --- a/libs/language-server/src/test/extension/lib/test-property-meta-inf.ts +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - CollectionValuetype, - IOType, - PrimitiveValuetypes, - evaluatePropertyValue, -} from '../../../lib'; - -export class TestPropertyMetaInformation extends BlockMetaInformation { - constructor() { - super( - // How the block type should be called: - 'TestProperty', - // Property definitions: - { - textProperty: { - type: PrimitiveValuetypes.Text, - }, - customValidationTextProperty: { - type: PrimitiveValuetypes.Text, - defaultValue: 'valid', - validation: (property, validationContext, evaluationContext) => { - const value = evaluatePropertyValue( - property, - evaluationContext, - PrimitiveValuetypes.Text, - ); - - if (value !== undefined && value !== 'valid') { - validationContext.accept('error', `Invalid value "${value}"`, { - node: property.value, - }); - } - }, - }, - booleanProperty: { - type: PrimitiveValuetypes.Boolean, - defaultValue: false, - }, - integerProperty: { - type: PrimitiveValuetypes.Integer, - defaultValue: 0, - }, - decimalProperty: { - type: PrimitiveValuetypes.Decimal, - defaultValue: 0.0, - }, - regexProperty: { - type: PrimitiveValuetypes.Regex, - defaultValue: /\r?\n/, - }, - textCollectionProperty: { - type: new CollectionValuetype(PrimitiveValuetypes.Text), - defaultValue: [], - }, - valuetypeAssignmentProperty: { - type: PrimitiveValuetypes.ValuetypeAssignment, - defaultValue: '"test" oftype text', - }, - }, - // Input type: - IOType.FILE, - - // Output type: - IOType.TABLE, - ); - } -} diff --git a/libs/language-server/src/test/index.ts b/libs/language-server/src/test/index.ts index fb4c055a2..fd181e695 100644 --- a/libs/language-server/src/test/index.ts +++ b/libs/language-server/src/test/index.ts @@ -4,4 +4,3 @@ export * from './langium-utils'; export * from './utils'; -export * from './extension'; diff --git a/libs/language-server/src/test/utils.ts b/libs/language-server/src/test/utils.ts index 4242129f9..2310e2c6c 100644 --- a/libs/language-server/src/test/utils.ts +++ b/libs/language-server/src/test/utils.ts @@ -7,14 +7,7 @@ import * as path from 'path'; import { AstNode, LangiumDocument, ValidationAcceptor } from 'langium'; -import { - BlockMetaInformation, - IOType, - blockMetaInfRegistry, - constraintMetaInfRegistry, -} from '../lib'; - -import { TestLangExtension } from './extension'; +import { blockMetaInfRegistry, constraintMetaInfRegistry } from '../lib'; // eslint-disable-next-line @typescript-eslint/no-empty-function export const validationAcceptorMockImpl: ValidationAcceptor = () => {}; @@ -50,18 +43,6 @@ export function expectNoParserAndLexerErrors( expect(document.parseResult.lexerErrors).toHaveLength(0); } -export function getTestExtensionBlockForIOType( - testExtension: TestLangExtension, - ioType: IOType, - io: 'input' | 'output', -): BlockMetaInformation { - const metaInf = testExtension.constructBlockMetaInformationFromIOType( - ioType, - io, - ); - return new metaInf(); -} - export function clearMetaInfRegistry() { blockMetaInfRegistry.clear(); constraintMetaInfRegistry.clear(); From ff1dacb356041ac7c2908559901bffbed54221ec Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Mon, 4 Sep 2023 16:36:19 +0200 Subject: [PATCH 04/43] Adapt tests to removal of extensions --- .../src/lib/ast/value-definition.spec.ts | 1 - .../constraint/length-constraint-meta-inf.spec.ts | 2 -- .../meta-inf-example-validation.spec.ts | 2 -- .../constraint/range-constraint-meta-inf.spec.ts | 2 -- .../src/lib/meta-information/block-meta-inf.ts | 4 ++++ .../validation/checks/block-definition.spec.ts | 2 -- .../checks/blocktype-definition.spec.ts | 2 -- .../src/lib/validation/checks/column-id.spec.ts | 2 -- .../checks/composite-blocktype-definition.spec.ts | 2 -- .../expression-constraint-definition.spec.ts | 2 -- .../lib/validation/checks/jayvee-model.spec.ts | 2 -- .../lib/validation/checks/pipe-definition.spec.ts | 2 -- .../validation/checks/pipeline-definition.spec.ts | 2 -- .../validation/checks/property-assignment.spec.ts | 7 +------ .../lib/validation/checks/property-body.spec.ts | 4 +--- .../lib/validation/checks/range-literal.spec.ts | 2 -- .../lib/validation/checks/regex-literal.spec.ts | 2 -- .../lib/validation/checks/transform-body.spec.ts | 2 -- .../checks/transform-output-assignment.spec.ts | 2 -- .../checks/typed-constraint-definition.spec.ts | 2 -- .../checks/valuetype-definition.spec.ts | 2 -- .../validation/checks/valuetype-reference.spec.ts | 2 -- .../src/lib/validation/validation-utils.spec.ts | 2 -- .../invalid-block-as-multiple-pipe-inputs.jv | 10 ++++++++++ .../block-definition/invalid-missing-pipe.jv | 5 +++++ .../invalid-output-block-as-input.jv | 10 ++++++++++ .../block-definition/valid-block-definition.jv | 10 ++++++++++ .../chained/invalid-pipe-between-blocktypes.jv | 10 ++++++++++ .../single/invalid-pipe-between-blocktypes.jv | 10 ++++++++++ .../assets/pipeline-definition/valid-pipeline.jv | 5 +++++ .../property-assignment/invalid-property-type.jv | 13 +++++++++++++ .../invalid-runtime-property.jv | 13 +++++++++++++ .../invalid-unknown-property.jv | 13 +++++++++++++ .../property-assignment/valid-runtime-property.jv | 13 +++++++++++++ .../valid-simplify-info-sub-expression.jv | 13 +++++++++++++ .../property-assignment/valid-simplify-info.jv | 13 +++++++++++++ .../valid-uneccessarysimplify-info.jv | 13 +++++++++++++ .../property-body/invalid-missing-property.jv | 7 +++++++ .../invalid-property-validation-failed.jv | 15 +++++++++++++++ .../assets/property-body/valid-default-values.jv | 7 +++++++ 40 files changed, 186 insertions(+), 48 deletions(-) diff --git a/libs/language-server/src/lib/ast/value-definition.spec.ts b/libs/language-server/src/lib/ast/value-definition.spec.ts index 781abb0f7..1479bc390 100644 --- a/libs/language-server/src/lib/ast/value-definition.spec.ts +++ b/libs/language-server/src/lib/ast/value-definition.spec.ts @@ -21,7 +21,6 @@ describe('Parsing of ValuetypeDefinition', () => { ); beforeAll(() => { - // TODO: fix tests after removing TestExtension const services = createJayveeServices(NodeFileSystem).Jayvee; parse = parseHelper(services); }); diff --git a/libs/language-server/src/lib/constraint/length-constraint-meta-inf.spec.ts b/libs/language-server/src/lib/constraint/length-constraint-meta-inf.spec.ts index 54c513114..00242ab94 100644 --- a/libs/language-server/src/lib/constraint/length-constraint-meta-inf.spec.ts +++ b/libs/language-server/src/lib/constraint/length-constraint-meta-inf.spec.ts @@ -52,8 +52,6 @@ describe('Validation of LengthConstraint', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/constraint/meta-inf-example-validation.spec.ts b/libs/language-server/src/lib/constraint/meta-inf-example-validation.spec.ts index b7e2f2834..2732985f6 100644 --- a/libs/language-server/src/lib/constraint/meta-inf-example-validation.spec.ts +++ b/libs/language-server/src/lib/constraint/meta-inf-example-validation.spec.ts @@ -15,8 +15,6 @@ describe('Validation of builtin examples of ConstraintMetaInformation', () => { let validate: (input: string) => Promise>; beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services services = createJayveeServices(NodeFileSystem).Jayvee; // Create validation helper for language services diff --git a/libs/language-server/src/lib/constraint/range-constraint-meta-inf.spec.ts b/libs/language-server/src/lib/constraint/range-constraint-meta-inf.spec.ts index 0a84895c9..7c2b1a7e5 100644 --- a/libs/language-server/src/lib/constraint/range-constraint-meta-inf.spec.ts +++ b/libs/language-server/src/lib/constraint/range-constraint-meta-inf.spec.ts @@ -52,8 +52,6 @@ describe('Validation of RangeConstraint', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/meta-information/block-meta-inf.ts b/libs/language-server/src/lib/meta-information/block-meta-inf.ts index 49af60541..4c8f046b6 100644 --- a/libs/language-server/src/lib/meta-information/block-meta-inf.ts +++ b/libs/language-server/src/lib/meta-information/block-meta-inf.ts @@ -68,6 +68,10 @@ export class BlockMetaInformation extends MetaInformation { ? toBeWrapped.ref : toBeWrapped; + if (blocktypeDefinition === undefined) { + return false; + } + // TODO: implement if (isBuiltinBlocktypeDefinition(blocktypeDefinition)) { return true; diff --git a/libs/language-server/src/lib/validation/checks/block-definition.spec.ts b/libs/language-server/src/lib/validation/checks/block-definition.spec.ts index e6411cbee..a8da55530 100644 --- a/libs/language-server/src/lib/validation/checks/block-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/block-definition.spec.ts @@ -51,8 +51,6 @@ describe('Validation of BlockDefinition', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/blocktype-definition.spec.ts b/libs/language-server/src/lib/validation/checks/blocktype-definition.spec.ts index de1f530b6..92563905b 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-definition.spec.ts @@ -54,8 +54,6 @@ describe('Validation of BuiltinBlocktypeDefinition', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/column-id.spec.ts b/libs/language-server/src/lib/validation/checks/column-id.spec.ts index 4742dd29f..42a36d5d1 100644 --- a/libs/language-server/src/lib/validation/checks/column-id.spec.ts +++ b/libs/language-server/src/lib/validation/checks/column-id.spec.ts @@ -48,8 +48,6 @@ describe('Validation of ColumnId', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts b/libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts index 26aa57d27..3da9d6656 100644 --- a/libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts @@ -54,8 +54,6 @@ describe('Validation of CompositeBlocktypeDefinition', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/expression-constraint-definition.spec.ts b/libs/language-server/src/lib/validation/checks/expression-constraint-definition.spec.ts index 7047b7ee8..6de6dcb89 100644 --- a/libs/language-server/src/lib/validation/checks/expression-constraint-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/expression-constraint-definition.spec.ts @@ -55,8 +55,6 @@ describe('Validation of ConstraintDefinition (expression syntax)', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/jayvee-model.spec.ts b/libs/language-server/src/lib/validation/checks/jayvee-model.spec.ts index 8668c5945..1eacf1a11 100644 --- a/libs/language-server/src/lib/validation/checks/jayvee-model.spec.ts +++ b/libs/language-server/src/lib/validation/checks/jayvee-model.spec.ts @@ -46,8 +46,6 @@ describe('Validation of JayveeModel', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; // Parse function for Jayvee (without validation) diff --git a/libs/language-server/src/lib/validation/checks/pipe-definition.spec.ts b/libs/language-server/src/lib/validation/checks/pipe-definition.spec.ts index 8620efa50..9aa8ff203 100644 --- a/libs/language-server/src/lib/validation/checks/pipe-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/pipe-definition.spec.ts @@ -48,8 +48,6 @@ describe('Validation of PipeDefinition', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/pipeline-definition.spec.ts b/libs/language-server/src/lib/validation/checks/pipeline-definition.spec.ts index fb4d19527..9b1dee65e 100644 --- a/libs/language-server/src/lib/validation/checks/pipeline-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/pipeline-definition.spec.ts @@ -51,8 +51,6 @@ describe('Validation of PipelineDefinition', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index 8d5110e66..9a9ec44c6 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -55,14 +55,11 @@ describe('Validation of PropertyAssignment', () => { const type = propertyBody.$container.type; let metaInf: MetaInformation | undefined; if (isReferenceableBlocktypeDefinition(type.ref)) { - if (!BlockMetaInformation.canBeWrapped(type.ref)) { - return; // TODO: is this the right to do here? - } metaInf = new BlockMetaInformation(type.ref); } else if (isBuiltinConstrainttypeDefinition(type.ref)) { metaInf = getConstraintMetaInf(type.ref); } - expect(metaInf === undefined); + expect(metaInf).toBeDefined(); const propertyAssignment = locator.getAstNode( propertyBody, @@ -78,8 +75,6 @@ describe('Validation of PropertyAssignment', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/property-body.spec.ts b/libs/language-server/src/lib/validation/checks/property-body.spec.ts index 311fe60b6..6a81c38de 100644 --- a/libs/language-server/src/lib/validation/checks/property-body.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-body.spec.ts @@ -54,8 +54,6 @@ describe('Validation PropertyBody', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; @@ -99,7 +97,7 @@ describe('Validation PropertyBody', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(1); expect(validationAcceptorMock).toHaveBeenCalledWith( 'error', - `Invalid value "invalid"`, + 'The value needs to be of type CustomValuetype but is of type text', expect.any(Object), ); }); diff --git a/libs/language-server/src/lib/validation/checks/range-literal.spec.ts b/libs/language-server/src/lib/validation/checks/range-literal.spec.ts index ffa8e24b9..7a37b330f 100644 --- a/libs/language-server/src/lib/validation/checks/range-literal.spec.ts +++ b/libs/language-server/src/lib/validation/checks/range-literal.spec.ts @@ -51,8 +51,6 @@ describe('Validation of RangeLiteral', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/regex-literal.spec.ts b/libs/language-server/src/lib/validation/checks/regex-literal.spec.ts index 79c0edc6c..321afef9f 100644 --- a/libs/language-server/src/lib/validation/checks/regex-literal.spec.ts +++ b/libs/language-server/src/lib/validation/checks/regex-literal.spec.ts @@ -51,8 +51,6 @@ describe('Validation of RegexLiteral', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/transform-body.spec.ts b/libs/language-server/src/lib/validation/checks/transform-body.spec.ts index 55492693e..f8d55703d 100644 --- a/libs/language-server/src/lib/validation/checks/transform-body.spec.ts +++ b/libs/language-server/src/lib/validation/checks/transform-body.spec.ts @@ -54,8 +54,6 @@ describe('Validation of TransformBody', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/transform-output-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/transform-output-assignment.spec.ts index f8f2d7d32..e36bbdb5b 100644 --- a/libs/language-server/src/lib/validation/checks/transform-output-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/transform-output-assignment.spec.ts @@ -55,8 +55,6 @@ describe('Validation of TransformOutputAssignment', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/typed-constraint-definition.spec.ts b/libs/language-server/src/lib/validation/checks/typed-constraint-definition.spec.ts index 10cf8c8ff..06d3e43e2 100644 --- a/libs/language-server/src/lib/validation/checks/typed-constraint-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/typed-constraint-definition.spec.ts @@ -51,8 +51,6 @@ describe('Validation of ConstraintDefinition (typed syntax)', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/valuetype-definition.spec.ts b/libs/language-server/src/lib/validation/checks/valuetype-definition.spec.ts index 9cb974f37..aa0714fcf 100644 --- a/libs/language-server/src/lib/validation/checks/valuetype-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/valuetype-definition.spec.ts @@ -54,8 +54,6 @@ describe('Validation of ValuetypeDefinition', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/valuetype-reference.spec.ts b/libs/language-server/src/lib/validation/checks/valuetype-reference.spec.ts index b04faa9cc..ce28b9ab7 100644 --- a/libs/language-server/src/lib/validation/checks/valuetype-reference.spec.ts +++ b/libs/language-server/src/lib/validation/checks/valuetype-reference.spec.ts @@ -63,8 +63,6 @@ describe('Validation of ValuetypeReference', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/validation-utils.spec.ts b/libs/language-server/src/lib/validation/validation-utils.spec.ts index 9b5087967..715e9e787 100644 --- a/libs/language-server/src/lib/validation/validation-utils.spec.ts +++ b/libs/language-server/src/lib/validation/validation-utils.spec.ts @@ -45,8 +45,6 @@ describe('Validation of validation-utils', () => { } beforeAll(() => { - // TODO: fix tests after removing TestExtension - // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/test/assets/block-definition/invalid-block-as-multiple-pipe-inputs.jv b/libs/language-server/src/test/assets/block-definition/invalid-block-as-multiple-pipe-inputs.jv index 023fadd73..5529c0ef1 100644 --- a/libs/language-server/src/test/assets/block-definition/invalid-block-as-multiple-pipe-inputs.jv +++ b/libs/language-server/src/test/assets/block-definition/invalid-block-as-multiple-pipe-inputs.jv @@ -13,3 +13,13 @@ pipeline Pipeline { BlockFrom -> BlockTo; } + +builtin blocktype TestFileExtractor { + input inPort oftype None; + output outPort oftype Table; +} + +builtin blocktype TestTableLoader { + input inPort oftype Table; + output outPort oftype None; +} diff --git a/libs/language-server/src/test/assets/block-definition/invalid-missing-pipe.jv b/libs/language-server/src/test/assets/block-definition/invalid-missing-pipe.jv index 913f9cca0..26af22d9e 100644 --- a/libs/language-server/src/test/assets/block-definition/invalid-missing-pipe.jv +++ b/libs/language-server/src/test/assets/block-definition/invalid-missing-pipe.jv @@ -6,3 +6,8 @@ pipeline Pipeline { block TestExtractor oftype TestFileExtractor { } } + +builtin blocktype TestFileExtractor { + input inPort oftype None; + output outPort oftype File; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/block-definition/invalid-output-block-as-input.jv b/libs/language-server/src/test/assets/block-definition/invalid-output-block-as-input.jv index 7f3dc414c..40f836c9b 100644 --- a/libs/language-server/src/test/assets/block-definition/invalid-output-block-as-input.jv +++ b/libs/language-server/src/test/assets/block-definition/invalid-output-block-as-input.jv @@ -13,3 +13,13 @@ pipeline Pipeline { BlockTo -> BlockFrom; } + +builtin blocktype TestFileExtractor { + input inPort oftype None; + output outPort oftype File; +} + +builtin blocktype TestTableLoader { + input inPort oftype File; + output outPort oftype None; +} diff --git a/libs/language-server/src/test/assets/block-definition/valid-block-definition.jv b/libs/language-server/src/test/assets/block-definition/valid-block-definition.jv index 9ae66b58d..272e0f9f7 100644 --- a/libs/language-server/src/test/assets/block-definition/valid-block-definition.jv +++ b/libs/language-server/src/test/assets/block-definition/valid-block-definition.jv @@ -11,3 +11,13 @@ pipeline Pipeline { TestExtractor -> TestLoader; } + +builtin blocktype TestFileExtractor { + input inPort oftype None; + output outPort oftype File; +} + +builtin blocktype TestTableLoader { + input inPort oftype File; + output outPort oftype None; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/pipe-definition/chained/invalid-pipe-between-blocktypes.jv b/libs/language-server/src/test/assets/pipe-definition/chained/invalid-pipe-between-blocktypes.jv index 9ae66b58d..65cc3933c 100644 --- a/libs/language-server/src/test/assets/pipe-definition/chained/invalid-pipe-between-blocktypes.jv +++ b/libs/language-server/src/test/assets/pipe-definition/chained/invalid-pipe-between-blocktypes.jv @@ -11,3 +11,13 @@ pipeline Pipeline { TestExtractor -> TestLoader; } + +builtin blocktype TestFileExtractor { + input inPort oftype None; + output outPort oftype File; +} + +builtin blocktype TestTableLoader { + input inPort oftype Table; + output outPort oftype None; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/pipe-definition/single/invalid-pipe-between-blocktypes.jv b/libs/language-server/src/test/assets/pipe-definition/single/invalid-pipe-between-blocktypes.jv index 1c4a9add6..2494fb23a 100644 --- a/libs/language-server/src/test/assets/pipe-definition/single/invalid-pipe-between-blocktypes.jv +++ b/libs/language-server/src/test/assets/pipe-definition/single/invalid-pipe-between-blocktypes.jv @@ -14,3 +14,13 @@ pipeline Pipeline { to: TestLoader; } } + +builtin blocktype TestFileExtractor { + input inPort oftype None; + output outPort oftype File; +} + +builtin blocktype TestTableLoader { + input inPort oftype Table; + output outPort oftype None; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/pipeline-definition/valid-pipeline.jv b/libs/language-server/src/test/assets/pipeline-definition/valid-pipeline.jv index 913f9cca0..26af22d9e 100644 --- a/libs/language-server/src/test/assets/pipeline-definition/valid-pipeline.jv +++ b/libs/language-server/src/test/assets/pipeline-definition/valid-pipeline.jv @@ -6,3 +6,8 @@ pipeline Pipeline { block TestExtractor oftype TestFileExtractor { } } + +builtin blocktype TestFileExtractor { + input inPort oftype None; + output outPort oftype File; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/invalid-property-type.jv b/libs/language-server/src/test/assets/property-assignment/invalid-property-type.jv index 0de16e942..f02bb85fe 100644 --- a/libs/language-server/src/test/assets/property-assignment/invalid-property-type.jv +++ b/libs/language-server/src/test/assets/property-assignment/invalid-property-type.jv @@ -7,3 +7,16 @@ pipeline Pipeline { textProperty: 2; } } + +builtin blocktype TestProperty { + input inPort oftype File; + output outPort oftype Table; + + property integerProperty oftype integer: 0; + property decimalProperty oftype integer: 0.0; + property textProperty oftype text; + property booleanProperty oftype boolean: false; + property regexProperty oftype Regex: /\r?\n/; + property textCollectionProperty oftype Collection: []; + property valuetypeAssignmentProperty oftype ValuetypeAssignment: "test" oftype text; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/invalid-runtime-property.jv b/libs/language-server/src/test/assets/property-assignment/invalid-runtime-property.jv index 8933ab4dd..29a0736b9 100644 --- a/libs/language-server/src/test/assets/property-assignment/invalid-runtime-property.jv +++ b/libs/language-server/src/test/assets/property-assignment/invalid-runtime-property.jv @@ -7,3 +7,16 @@ pipeline Pipeline { regexProperty: requires REGEX_ENV; } } + +builtin blocktype TestProperty { + input inPort oftype File; + output outPort oftype Table; + + property integerProperty oftype integer: 0; + property decimalProperty oftype integer: 0.0; + property textProperty oftype text; + property booleanProperty oftype boolean: false; + property regexProperty oftype Regex: /\r?\n/; + property textCollectionProperty oftype Collection: []; + property valuetypeAssignmentProperty oftype ValuetypeAssignment: "test" oftype text; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/invalid-unknown-property.jv b/libs/language-server/src/test/assets/property-assignment/invalid-unknown-property.jv index d49b93b9e..cf0a8e941 100644 --- a/libs/language-server/src/test/assets/property-assignment/invalid-unknown-property.jv +++ b/libs/language-server/src/test/assets/property-assignment/invalid-unknown-property.jv @@ -7,3 +7,16 @@ pipeline Pipeline { unknownProperty: ''; } } + +builtin blocktype TestProperty { + input inPort oftype File; + output outPort oftype Table; + + property integerProperty oftype integer: 0; + property decimalProperty oftype integer: 0.0; + property textProperty oftype text; + property booleanProperty oftype boolean: false; + property regexProperty oftype Regex: /\r?\n/; + property textCollectionProperty oftype Collection: []; + property valuetypeAssignmentProperty oftype ValuetypeAssignment: "test" oftype text; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/valid-runtime-property.jv b/libs/language-server/src/test/assets/property-assignment/valid-runtime-property.jv index 66b1b7e5c..6fddbd709 100644 --- a/libs/language-server/src/test/assets/property-assignment/valid-runtime-property.jv +++ b/libs/language-server/src/test/assets/property-assignment/valid-runtime-property.jv @@ -7,3 +7,16 @@ pipeline Pipeline { textProperty: requires TEXT_ENV; } } + +builtin blocktype TestProperty { + input inPort oftype File; + output outPort oftype Table; + + property integerProperty oftype integer: 0; + property decimalProperty oftype integer: 0.0; + property textProperty oftype text; + property booleanProperty oftype boolean: false; + property regexProperty oftype Regex: /\r?\n/; + property textCollectionProperty oftype Collection: []; + property valuetypeAssignmentProperty oftype ValuetypeAssignment: "test" oftype text; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/valid-simplify-info-sub-expression.jv b/libs/language-server/src/test/assets/property-assignment/valid-simplify-info-sub-expression.jv index 4541baab1..78d58798b 100644 --- a/libs/language-server/src/test/assets/property-assignment/valid-simplify-info-sub-expression.jv +++ b/libs/language-server/src/test/assets/property-assignment/valid-simplify-info-sub-expression.jv @@ -7,3 +7,16 @@ pipeline Pipeline { integerProperty: 10 + (10 + 10); } } + +builtin blocktype TestProperty { + input inPort oftype File; + output outPort oftype Table; + + property integerProperty oftype integer: 0; + property decimalProperty oftype integer: 0.0; + property textProperty oftype text; + property booleanProperty oftype boolean: false; + property regexProperty oftype Regex: /\r?\n/; + property textCollectionProperty oftype Collection: []; + property valuetypeAssignmentProperty oftype ValuetypeAssignment: "test" oftype text; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/valid-simplify-info.jv b/libs/language-server/src/test/assets/property-assignment/valid-simplify-info.jv index 90a83f5cc..4a5e07564 100644 --- a/libs/language-server/src/test/assets/property-assignment/valid-simplify-info.jv +++ b/libs/language-server/src/test/assets/property-assignment/valid-simplify-info.jv @@ -7,3 +7,16 @@ pipeline Pipeline { integerProperty: 345 + 674; } } + +builtin blocktype TestProperty { + input inPort oftype File; + output outPort oftype Table; + + property integerProperty oftype integer: 0; + property decimalProperty oftype integer: 0.0; + property textProperty oftype text; + property booleanProperty oftype boolean: false; + property regexProperty oftype Regex: /\r?\n/; + property textCollectionProperty oftype Collection: []; + property valuetypeAssignmentProperty oftype ValuetypeAssignment: "test" oftype text; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/valid-uneccessarysimplify-info.jv b/libs/language-server/src/test/assets/property-assignment/valid-uneccessarysimplify-info.jv index ef804eb18..a30fccf5e 100644 --- a/libs/language-server/src/test/assets/property-assignment/valid-uneccessarysimplify-info.jv +++ b/libs/language-server/src/test/assets/property-assignment/valid-uneccessarysimplify-info.jv @@ -7,3 +7,16 @@ pipeline Pipeline { integerProperty: -674; } } + +builtin blocktype TestProperty { + input inPort oftype File; + output outPort oftype Table; + + property integerProperty oftype integer: 0; + property decimalProperty oftype integer: 0.0; + property textProperty oftype text; + property booleanProperty oftype boolean: false; + property regexProperty oftype Regex: /\r?\n/; + property textCollectionProperty oftype Collection: []; + property valuetypeAssignmentProperty oftype ValuetypeAssignment: "test" oftype text; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-body/invalid-missing-property.jv b/libs/language-server/src/test/assets/property-body/invalid-missing-property.jv index b7960bdff..559cc719e 100644 --- a/libs/language-server/src/test/assets/property-body/invalid-missing-property.jv +++ b/libs/language-server/src/test/assets/property-body/invalid-missing-property.jv @@ -6,3 +6,10 @@ pipeline Pipeline { block Test oftype TestProperty { } } + +builtin blocktype TestProperty { + input inPort oftype None; + output outPort oftype None; + + property textProperty oftype text; +} diff --git a/libs/language-server/src/test/assets/property-body/invalid-property-validation-failed.jv b/libs/language-server/src/test/assets/property-body/invalid-property-validation-failed.jv index 28f652381..fc143ce17 100644 --- a/libs/language-server/src/test/assets/property-body/invalid-property-validation-failed.jv +++ b/libs/language-server/src/test/assets/property-body/invalid-property-validation-failed.jv @@ -8,3 +8,18 @@ pipeline Pipeline { customValidationTextProperty: 'invalid'; } } + +builtin blocktype TestProperty { + input inPort oftype None; + output outPort oftype None; + + property textProperty oftype text; + property customValidationTextProperty oftype CustomValuetype; +} + +valuetype CustomValuetype oftype text { + constraints: [CustomConstraint]; +} + +constraint CustomConstraint on text: + value in ['valid']; diff --git a/libs/language-server/src/test/assets/property-body/valid-default-values.jv b/libs/language-server/src/test/assets/property-body/valid-default-values.jv index 7663c93b1..3baabcc1e 100644 --- a/libs/language-server/src/test/assets/property-body/valid-default-values.jv +++ b/libs/language-server/src/test/assets/property-body/valid-default-values.jv @@ -7,3 +7,10 @@ pipeline Pipeline { textProperty: ''; } } + +builtin blocktype TestProperty { + input inPort oftype None; + output outPort oftype None; + + property textProperty oftype text; +} From a1f5ffe86d466b3fd33e063852f25480874cc08e Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Mon, 4 Sep 2023 19:04:00 +0200 Subject: [PATCH 05/43] Replace lang extensions by builtin blocktype definitions --- apps/vs-code-extension/src/language-server.ts | 8 +- .../standard-library-file-system-provider.ts | 8 +- example/test.jv | 19 + libs/execution/src/lib/execution-context.ts | 5 +- libs/extensions/rdbms/lang/.babelrc | 10 - libs/extensions/rdbms/lang/.babelrc.license | 3 - libs/extensions/rdbms/lang/.eslintrc.json | 18 - .../rdbms/lang/.eslintrc.json.license | 3 - libs/extensions/rdbms/lang/README.md | 17 - libs/extensions/rdbms/lang/jest.config.ts | 18 - libs/extensions/rdbms/lang/package.json | 4 - .../rdbms/lang/package.json.license | 3 - libs/extensions/rdbms/lang/project.json | 34 -- .../rdbms/lang/project.json.license | 3 - libs/extensions/rdbms/lang/src/extension.ts | 20 - libs/extensions/rdbms/lang/src/index.ts | 5 - libs/extensions/rdbms/lang/src/lib/index.ts | 6 - .../lib/postgres-loader-meta-information.ts | 74 ---- .../src/lib/sqlite-loader-meta-information.ts | 55 --- libs/extensions/rdbms/lang/tsconfig.json | 22 - .../rdbms/lang/tsconfig.json.license | 3 - libs/extensions/rdbms/lang/tsconfig.lib.json | 10 - .../rdbms/lang/tsconfig.lib.json.license | 3 - libs/extensions/rdbms/lang/tsconfig.spec.json | 14 - .../rdbms/lang/tsconfig.spec.json.license | 3 - libs/extensions/std/lang/.babelrc | 10 - libs/extensions/std/lang/.babelrc.license | 3 - libs/extensions/std/lang/.eslintrc.json | 18 - .../std/lang/.eslintrc.json.license | 3 - libs/extensions/std/lang/README.md | 17 - libs/extensions/std/lang/jest.config.ts | 18 - libs/extensions/std/lang/package.json | 4 - libs/extensions/std/lang/package.json.license | 3 - libs/extensions/std/lang/project.json | 34 -- libs/extensions/std/lang/project.json.license | 3 - .../lang/src/archive-interpreter-meta-inf.ts | 46 -- .../std/lang/src/example-validation.spec.ts | 51 --- libs/extensions/std/lang/src/extension.ts | 39 -- .../std/lang/src/file-picker-meta-inf.ts | 46 -- .../src/gtfs-rt-interpreter-meta-inf.spec.ts | 64 --- .../lang/src/gtfs-rt-interpreter-meta-inf.ts | 124 ------ .../std/lang/src/http-extractor-meta-inf.ts | 185 -------- libs/extensions/std/lang/src/index.ts | 5 - .../src/meta-inf-example-validation.spec.ts | 135 ------ .../text-file-interpreter-meta-inf.spec.ts | 64 --- .../src/text-file-interpreter-meta-inf.ts | 64 --- .../src/text-line-deleter-meta-inf.spec.ts | 64 --- .../lang/src/text-line-deleter-meta-inf.ts | 53 --- .../src/text-range-selector-meta-inf.spec.ts | 101 ----- .../lang/src/text-range-selector-meta-inf.ts | 101 ----- .../invalid-invalid-entity-param.jv | 17 - .../valid-valid-entity-param.jv | 17 - .../invalid-invalid-encoding-param.jv | 17 - .../valid-utf8-encoding.jv | 17 - .../invalid-line-less-or-equal-zero.jv | 17 - .../valid-postive-line-number.jv | 17 - .../invalid-lineFrom-greater-lineTo.jv | 18 - .../invalid-lineFrom-less-or-equal-zero.jv | 17 - .../invalid-lineTo-less-or-equal-zero.jv | 18 - .../valid-correct-range.jv | 18 - libs/extensions/std/lang/tsconfig.json | 22 - .../extensions/std/lang/tsconfig.json.license | 3 - libs/extensions/std/lang/tsconfig.lib.json | 10 - .../std/lang/tsconfig.lib.json.license | 3 - libs/extensions/std/lang/tsconfig.spec.json | 14 - .../std/lang/tsconfig.spec.json.license | 3 - libs/extensions/tabular/lang/.babelrc | 10 - libs/extensions/tabular/lang/.babelrc.license | 3 - libs/extensions/tabular/lang/.eslintrc.json | 18 - .../tabular/lang/.eslintrc.json.license | 3 - libs/extensions/tabular/lang/README.md | 17 - libs/extensions/tabular/lang/jest.config.ts | 18 - libs/extensions/tabular/lang/package.json | 4 - .../tabular/lang/package.json.license | 3 - libs/extensions/tabular/lang/project.json | 34 -- .../tabular/lang/project.json.license | 3 - libs/extensions/tabular/lang/src/extension.ts | 35 -- libs/extensions/tabular/lang/src/index.ts | 5 - .../src/lib/cell-range-selector-meta-inf.ts | 47 -- .../lang/src/lib/cell-writer-meta-inf.spec.ts | 90 ---- .../lang/src/lib/cell-writer-meta-inf.ts | 137 ------ .../src/lib/column-deleter-meta-inf.spec.ts | 67 --- .../lang/src/lib/column-deleter-meta-inf.ts | 72 ---- .../lang/src/lib/csv-interpreter-meta-inf.ts | 69 --- .../lang/src/lib/row-deleter-meta-inf.spec.ts | 65 --- .../lang/src/lib/row-deleter-meta-inf.ts | 73 ---- .../src/lib/sheet-picker-meta-inf.spec.ts | 67 --- .../lang/src/lib/sheet-picker-meta-inf.ts | 44 -- .../lib/table-interpreter-meta-inf.spec.ts | 70 --- .../src/lib/table-interpreter-meta-inf.ts | 105 ----- .../lib/table-transformer-meta-inf.spec.ts | 67 --- .../src/lib/table-transformer-meta-inf.ts | 149 ------- .../src/lib/xlsx-interpreter-meta-inf.spec.ts | 49 --- .../lang/src/lib/xlsx-interpreter-meta-inf.ts | 33 -- ...-write-length-does-not-match-cell-range.jv | 18 - .../invalid-wrong-at-dimension.jv | 18 - .../valid-range-matches-array-length.jv | 18 - .../invalid-partial-column-delete.jv | 17 - .../valid-column-delete.jv | 17 - .../invalid-partial-row-delete.jv | 17 - .../row-deleter-meta-inf/valid-row-delete.jv | 17 - .../invalid-sheet-picker-missing-parameter.jv | 17 - .../valid-correct-sheet-picker.jv | 18 - .../invalid-non-unique-column-names.jv | 21 - .../valid-correct-table.jv | 21 - ...-input-columns-transform-port-missmatch.jv | 26 -- .../valid-correct-ports.jv | 26 -- .../valid-xlsx-interpreter.jv | 17 - libs/extensions/tabular/lang/tsconfig.json | 22 - .../tabular/lang/tsconfig.json.license | 3 - .../extensions/tabular/lang/tsconfig.lib.json | 10 - .../tabular/lang/tsconfig.lib.json.license | 3 - .../tabular/lang/tsconfig.spec.json | 14 - .../tabular/lang/tsconfig.spec.json.license | 3 - libs/interpreter-lib/src/interpreter.ts | 3 - libs/interpreter-lib/src/parsing-util.ts | 1 + .../completion/jayvee-completion-provider.ts | 42 +- libs/language-server/src/lib/extension.ts | 15 - .../lib/meta-information/block-meta-inf.ts | 18 +- .../lib/meta-information/meta-inf-registry.ts | 65 +-- libs/language-server/src/stdlib/blocktypes.jv | 406 ------------------ .../builtin-blocktypes/ArchiveInterpreter.jv | 22 + .../builtin-blocktypes/CellRangeSelector.jv | 15 + .../stdlib/builtin-blocktypes/CellWriter.jv | 25 ++ .../builtin-blocktypes/ColumnDeleter.jv | 15 + .../builtin-blocktypes/CsvInterpreter.jv | 19 + .../stdlib/builtin-blocktypes/FilePicker.jv | 15 + .../builtin-blocktypes/GtfsRtInterpreter.jv | 70 +++ .../builtin-blocktypes/HttpExtractor.jv | 45 ++ .../builtin-blocktypes/PostgresLoader.jv | 30 ++ .../stdlib/builtin-blocktypes/RowDeleter.jv | 15 + .../stdlib/builtin-blocktypes/SheetPicker.jv | 15 + .../stdlib/builtin-blocktypes/SqliteLoader.jv | 20 + .../builtin-blocktypes/TableInterpreter.jv | 32 ++ .../builtin-blocktypes/TableTransformer.jv | 45 ++ .../builtin-blocktypes/TextFileInterpreter.jv | 21 + .../builtin-blocktypes/TextLineDeleter.jv | 17 + .../builtin-blocktypes/TextRangeSelector.jv | 11 + .../builtin-blocktypes/XlsInterpreter.jv | 11 + tsconfig.base.json | 9 - 140 files changed, 512 insertions(+), 4021 deletions(-) create mode 100644 example/test.jv delete mode 100644 libs/extensions/rdbms/lang/.babelrc delete mode 100644 libs/extensions/rdbms/lang/.babelrc.license delete mode 100644 libs/extensions/rdbms/lang/.eslintrc.json delete mode 100644 libs/extensions/rdbms/lang/.eslintrc.json.license delete mode 100644 libs/extensions/rdbms/lang/README.md delete mode 100644 libs/extensions/rdbms/lang/jest.config.ts delete mode 100644 libs/extensions/rdbms/lang/package.json delete mode 100644 libs/extensions/rdbms/lang/package.json.license delete mode 100644 libs/extensions/rdbms/lang/project.json delete mode 100644 libs/extensions/rdbms/lang/project.json.license delete mode 100644 libs/extensions/rdbms/lang/src/extension.ts delete mode 100644 libs/extensions/rdbms/lang/src/index.ts delete mode 100644 libs/extensions/rdbms/lang/src/lib/index.ts delete mode 100644 libs/extensions/rdbms/lang/src/lib/postgres-loader-meta-information.ts delete mode 100644 libs/extensions/rdbms/lang/src/lib/sqlite-loader-meta-information.ts delete mode 100644 libs/extensions/rdbms/lang/tsconfig.json delete mode 100644 libs/extensions/rdbms/lang/tsconfig.json.license delete mode 100644 libs/extensions/rdbms/lang/tsconfig.lib.json delete mode 100644 libs/extensions/rdbms/lang/tsconfig.lib.json.license delete mode 100644 libs/extensions/rdbms/lang/tsconfig.spec.json delete mode 100644 libs/extensions/rdbms/lang/tsconfig.spec.json.license delete mode 100644 libs/extensions/std/lang/.babelrc delete mode 100644 libs/extensions/std/lang/.babelrc.license delete mode 100644 libs/extensions/std/lang/.eslintrc.json delete mode 100644 libs/extensions/std/lang/.eslintrc.json.license delete mode 100644 libs/extensions/std/lang/README.md delete mode 100644 libs/extensions/std/lang/jest.config.ts delete mode 100644 libs/extensions/std/lang/package.json delete mode 100644 libs/extensions/std/lang/package.json.license delete mode 100644 libs/extensions/std/lang/project.json delete mode 100644 libs/extensions/std/lang/project.json.license delete mode 100644 libs/extensions/std/lang/src/archive-interpreter-meta-inf.ts delete mode 100644 libs/extensions/std/lang/src/example-validation.spec.ts delete mode 100644 libs/extensions/std/lang/src/extension.ts delete mode 100644 libs/extensions/std/lang/src/file-picker-meta-inf.ts delete mode 100644 libs/extensions/std/lang/src/gtfs-rt-interpreter-meta-inf.spec.ts delete mode 100644 libs/extensions/std/lang/src/gtfs-rt-interpreter-meta-inf.ts delete mode 100644 libs/extensions/std/lang/src/http-extractor-meta-inf.ts delete mode 100644 libs/extensions/std/lang/src/index.ts delete mode 100644 libs/extensions/std/lang/src/meta-inf-example-validation.spec.ts delete mode 100644 libs/extensions/std/lang/src/text-file-interpreter-meta-inf.spec.ts delete mode 100644 libs/extensions/std/lang/src/text-file-interpreter-meta-inf.ts delete mode 100644 libs/extensions/std/lang/src/text-line-deleter-meta-inf.spec.ts delete mode 100644 libs/extensions/std/lang/src/text-line-deleter-meta-inf.ts delete mode 100644 libs/extensions/std/lang/src/text-range-selector-meta-inf.spec.ts delete mode 100644 libs/extensions/std/lang/src/text-range-selector-meta-inf.ts delete mode 100644 libs/extensions/std/lang/test/assets/gtfs-rt-interpreter-meta-inf/invalid-invalid-entity-param.jv delete mode 100644 libs/extensions/std/lang/test/assets/gtfs-rt-interpreter-meta-inf/valid-valid-entity-param.jv delete mode 100644 libs/extensions/std/lang/test/assets/text-file-interpreter-meta-inf/invalid-invalid-encoding-param.jv delete mode 100644 libs/extensions/std/lang/test/assets/text-file-interpreter-meta-inf/valid-utf8-encoding.jv delete mode 100644 libs/extensions/std/lang/test/assets/text-line-deleter-meta-inf/invalid-line-less-or-equal-zero.jv delete mode 100644 libs/extensions/std/lang/test/assets/text-line-deleter-meta-inf/valid-postive-line-number.jv delete mode 100644 libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineFrom-greater-lineTo.jv delete mode 100644 libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineFrom-less-or-equal-zero.jv delete mode 100644 libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineTo-less-or-equal-zero.jv delete mode 100644 libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/valid-correct-range.jv delete mode 100644 libs/extensions/std/lang/tsconfig.json delete mode 100644 libs/extensions/std/lang/tsconfig.json.license delete mode 100644 libs/extensions/std/lang/tsconfig.lib.json delete mode 100644 libs/extensions/std/lang/tsconfig.lib.json.license delete mode 100644 libs/extensions/std/lang/tsconfig.spec.json delete mode 100644 libs/extensions/std/lang/tsconfig.spec.json.license delete mode 100644 libs/extensions/tabular/lang/.babelrc delete mode 100644 libs/extensions/tabular/lang/.babelrc.license delete mode 100644 libs/extensions/tabular/lang/.eslintrc.json delete mode 100644 libs/extensions/tabular/lang/.eslintrc.json.license delete mode 100644 libs/extensions/tabular/lang/README.md delete mode 100644 libs/extensions/tabular/lang/jest.config.ts delete mode 100644 libs/extensions/tabular/lang/package.json delete mode 100644 libs/extensions/tabular/lang/package.json.license delete mode 100644 libs/extensions/tabular/lang/project.json delete mode 100644 libs/extensions/tabular/lang/project.json.license delete mode 100644 libs/extensions/tabular/lang/src/extension.ts delete mode 100644 libs/extensions/tabular/lang/src/index.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/cell-range-selector-meta-inf.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/cell-writer-meta-inf.spec.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/cell-writer-meta-inf.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/column-deleter-meta-inf.spec.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/column-deleter-meta-inf.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/csv-interpreter-meta-inf.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/row-deleter-meta-inf.spec.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/row-deleter-meta-inf.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/sheet-picker-meta-inf.spec.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/sheet-picker-meta-inf.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/table-interpreter-meta-inf.spec.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/table-interpreter-meta-inf.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/table-transformer-meta-inf.spec.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/table-transformer-meta-inf.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/xlsx-interpreter-meta-inf.spec.ts delete mode 100644 libs/extensions/tabular/lang/src/lib/xlsx-interpreter-meta-inf.ts delete mode 100644 libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/invalid-write-length-does-not-match-cell-range.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/invalid-wrong-at-dimension.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/valid-range-matches-array-length.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/column-deleter-meta-inf/invalid-partial-column-delete.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/column-deleter-meta-inf/valid-column-delete.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/row-deleter-meta-inf/invalid-partial-row-delete.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/row-deleter-meta-inf/valid-row-delete.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/sheet-picker-meta-inf/invalid-sheet-picker-missing-parameter.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/sheet-picker-meta-inf/valid-correct-sheet-picker.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/table-interpreter-meta-inf/invalid-non-unique-column-names.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/table-interpreter-meta-inf/valid-correct-table.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/table-transformer-meta-inf/invalid-input-columns-transform-port-missmatch.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/table-transformer-meta-inf/valid-correct-ports.jv delete mode 100644 libs/extensions/tabular/lang/test/assets/xlsx-interpreter-meta-inf/valid-xlsx-interpreter.jv delete mode 100644 libs/extensions/tabular/lang/tsconfig.json delete mode 100644 libs/extensions/tabular/lang/tsconfig.json.license delete mode 100644 libs/extensions/tabular/lang/tsconfig.lib.json delete mode 100644 libs/extensions/tabular/lang/tsconfig.lib.json.license delete mode 100644 libs/extensions/tabular/lang/tsconfig.spec.json delete mode 100644 libs/extensions/tabular/lang/tsconfig.spec.json.license delete mode 100644 libs/language-server/src/lib/extension.ts delete mode 100644 libs/language-server/src/stdlib/blocktypes.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv create mode 100644 libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv diff --git a/apps/vs-code-extension/src/language-server.ts b/apps/vs-code-extension/src/language-server.ts index 21595f4c3..e03b1c248 100644 --- a/apps/vs-code-extension/src/language-server.ts +++ b/apps/vs-code-extension/src/language-server.ts @@ -2,11 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { StdLangExtension } from '@jvalue/jayvee-extensions/std/lang'; -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; +import { createJayveeServices } from '@jvalue/jayvee-language-server'; import { startLanguageServer } from 'langium'; import { NodeFileSystem } from 'langium/node'; import { ProposedFeatures, createConnection } from 'vscode-languageserver/node'; @@ -14,8 +10,6 @@ import { ProposedFeatures, createConnection } from 'vscode-languageserver/node'; // Create a connection to the client const connection = createConnection(ProposedFeatures.all); -useExtension(new StdLangExtension()); - // Inject the shared services and language-specific services const { shared } = createJayveeServices({ connection, diff --git a/apps/vs-code-extension/src/standard-library-file-system-provider.ts b/apps/vs-code-extension/src/standard-library-file-system-provider.ts index 862ff9eaa..180c81675 100644 --- a/apps/vs-code-extension/src/standard-library-file-system-provider.ts +++ b/apps/vs-code-extension/src/standard-library-file-system-provider.ts @@ -2,12 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { StdLangExtension } from '@jvalue/jayvee-extensions/std/lang'; -import { - getStdLib, - registerConstraints, - useExtension as useLangExtension, -} from '@jvalue/jayvee-language-server'; +import { getStdLib, registerConstraints } from '@jvalue/jayvee-language-server'; import { EventEmitter, ExtensionContext, @@ -34,7 +29,6 @@ export class StandardLibraryFileSystemProvider implements FileSystemProvider { private registerStdLib() { // The VSCode Extension needs to register the StdLangExtension, // otherwise the StdLib does not include the blocktype definitions. - useLangExtension(new StdLangExtension()); registerConstraints(); Object.entries(getStdLib()).forEach(([libName, lib]) => { diff --git a/example/test.jv b/example/test.jv new file mode 100644 index 000000000..8f2337c4e --- /dev/null +++ b/example/test.jv @@ -0,0 +1,19 @@ +/* +Interprets an input file as a csv-file containing string-values delimited by `delimiter` and outputs a `Sheet`. + +@example Interprets an input file as a csv-file containing string-values delimited by `;` and outputs `Sheet`. +block AgencyCSVInterpreter oftype CSVInterpreter { + delimiter: ";"; + } +*/ +builtin blocktype CSVInterpreter { + input default oftype TextFile; + output default oftype Sheet; + + // The delimiter for values in the CSV file. + property delimiter oftype text: ','; + // The enclosing character that may be used for values in the CSV file. + property enclosing oftype text: ''; + // The character to escape enclosing characters in values. + property enclosingEscape oftype text: ''; +} \ No newline at end of file diff --git a/libs/execution/src/lib/execution-context.ts b/libs/execution/src/lib/execution-context.ts index 05123b152..8253fcc44 100644 --- a/libs/execution/src/lib/execution-context.ts +++ b/libs/execution/src/lib/execution-context.ts @@ -6,6 +6,7 @@ import { strict as assert } from 'assert'; import { BlockDefinition, + BlockMetaInformation, ConstraintDefinition, EvaluationContext, InternalValueRepresentation, @@ -14,7 +15,6 @@ import { TransformDefinition, Valuetype, evaluatePropertyValue, - getOrFailBockMetaInf, getOrFailConstraintMetaInf, isBlockDefinition, isExpressionConstraintDefinition, @@ -150,7 +150,8 @@ export class ExecutionContext { return getOrFailConstraintMetaInf(currentNode.type); } else if (isBlockDefinition(currentNode)) { assert(isReference(currentNode.type)); - return getOrFailBockMetaInf(currentNode.type); + assert(BlockMetaInformation.canBeWrapped(currentNode.type)); + return new BlockMetaInformation(currentNode.type); } assertUnreachable(currentNode); } diff --git a/libs/extensions/rdbms/lang/.babelrc b/libs/extensions/rdbms/lang/.babelrc deleted file mode 100644 index e24a5465f..000000000 --- a/libs/extensions/rdbms/lang/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@nrwl/web/babel", - { - "useBuiltIns": "usage" - } - ] - ] -} diff --git a/libs/extensions/rdbms/lang/.babelrc.license b/libs/extensions/rdbms/lang/.babelrc.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/rdbms/lang/.babelrc.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/rdbms/lang/.eslintrc.json b/libs/extensions/rdbms/lang/.eslintrc.json deleted file mode 100644 index 632e9b0e2..000000000 --- a/libs/extensions/rdbms/lang/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": ["../../../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} - }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/libs/extensions/rdbms/lang/.eslintrc.json.license b/libs/extensions/rdbms/lang/.eslintrc.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/rdbms/lang/.eslintrc.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/rdbms/lang/README.md b/libs/extensions/rdbms/lang/README.md deleted file mode 100644 index f29a26396..000000000 --- a/libs/extensions/rdbms/lang/README.md +++ /dev/null @@ -1,17 +0,0 @@ - - -# extensions-rdbms - -This library was generated with [Nx](https://nx.dev). - -## Building - -Run `nx build extensions-rdbms` to build the library. - -## Running unit tests - -Run `nx test extensions-rdbms` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/extensions/rdbms/lang/jest.config.ts b/libs/extensions/rdbms/lang/jest.config.ts deleted file mode 100644 index 94553f702..000000000 --- a/libs/extensions/rdbms/lang/jest.config.ts +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -export default { - displayName: 'extensions-rdbms', - preset: '../../../../jest.preset.js', - globals: { - 'ts-jest': { - tsconfig: '/tsconfig.spec.json', - }, - }, - transform: { - '^.+\\.[tj]s$': 'ts-jest', - }, - moduleFileExtensions: ['ts', 'js', 'html'], - coverageDirectory: '../../../coverage/libs/extensions/rdbms', -}; diff --git a/libs/extensions/rdbms/lang/package.json b/libs/extensions/rdbms/lang/package.json deleted file mode 100644 index d72af8ee2..000000000 --- a/libs/extensions/rdbms/lang/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "@jvalue/jayvee-extensions/rdbms/lang", - "type": "commonjs" -} diff --git a/libs/extensions/rdbms/lang/package.json.license b/libs/extensions/rdbms/lang/package.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/rdbms/lang/package.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/rdbms/lang/project.json b/libs/extensions/rdbms/lang/project.json deleted file mode 100644 index b92c660f7..000000000 --- a/libs/extensions/rdbms/lang/project.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "extensions-rdbms-lang", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "libs/extensions/rdbms/lang/src", - "projectType": "library", - "targets": { - "build": { - "executor": "@nrwl/js:tsc", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/libs/extensions/rdbms/lang", - "main": "libs/extensions/rdbms/lang/src/index.ts", - "tsConfig": "libs/extensions/rdbms/lang/tsconfig.lib.json", - "assets": ["libs/extensions/rdbms/lang/*.md"] - } - }, - "lint": { - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["libs/extensions/rdbms/lang/**/*.ts"] - } - }, - "test": { - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "libs/extensions/rdbms/lang/jest.config.ts", - "passWithNoTests": true - } - } - }, - "tags": [] -} diff --git a/libs/extensions/rdbms/lang/project.json.license b/libs/extensions/rdbms/lang/project.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/rdbms/lang/project.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/rdbms/lang/src/extension.ts b/libs/extensions/rdbms/lang/src/extension.ts deleted file mode 100644 index 067bc8eb6..000000000 --- a/libs/extensions/rdbms/lang/src/extension.ts +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - ConstructorClass, - JayveeLangExtension, -} from '@jvalue/jayvee-language-server'; - -import { - PostgresLoaderMetaInformation, - SQLiteLoaderMetaInformation, -} from './lib'; - -export class RdbmsLangExtension implements JayveeLangExtension { - getBlockMetaInf(): Array> { - return [PostgresLoaderMetaInformation, SQLiteLoaderMetaInformation]; - } -} diff --git a/libs/extensions/rdbms/lang/src/index.ts b/libs/extensions/rdbms/lang/src/index.ts deleted file mode 100644 index 88d3a0045..000000000 --- a/libs/extensions/rdbms/lang/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -export * from './extension'; diff --git a/libs/extensions/rdbms/lang/src/lib/index.ts b/libs/extensions/rdbms/lang/src/lib/index.ts deleted file mode 100644 index 4d82edcaf..000000000 --- a/libs/extensions/rdbms/lang/src/lib/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -export * from './postgres-loader-meta-information'; -export * from './sqlite-loader-meta-information'; diff --git a/libs/extensions/rdbms/lang/src/lib/postgres-loader-meta-information.ts b/libs/extensions/rdbms/lang/src/lib/postgres-loader-meta-information.ts deleted file mode 100644 index d963ba778..000000000 --- a/libs/extensions/rdbms/lang/src/lib/postgres-loader-meta-information.ts +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - IOType, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; - -export class PostgresLoaderMetaInformation extends BlockMetaInformation { - constructor() { - super( - 'PostgresLoader', - { - host: { - type: PrimitiveValuetypes.Text, - docs: { - description: 'The hostname or IP address of the Postgres database.', - }, - }, - port: { - type: PrimitiveValuetypes.Integer, - docs: { - description: 'The port of the Postgres database.', - }, - }, - username: { - type: PrimitiveValuetypes.Text, - docs: { - description: 'The username to login to the Postgres database.', - }, - }, - password: { - type: PrimitiveValuetypes.Text, - docs: { - description: 'The password to login to the Postgres database.', - }, - }, - database: { - type: PrimitiveValuetypes.Text, - docs: { - description: 'The database to use.', - }, - }, - table: { - type: PrimitiveValuetypes.Text, - docs: { - description: 'The name of the table to write into.', - }, - }, - }, - IOType.TABLE, - IOType.NONE, - ); - this.docs.description = 'Loads a `Table` into a PostgreSQL database sink.'; - this.docs.examples = [ - { - code: blockExampleUsage, - description: - 'A local Postgres instance is filled with table data about cars.', - }, - ]; - } -} - -const blockExampleUsage = `block CarsLoader oftype PostgresLoader { - host: "localhost"; - port: 5432; - username: "postgres"; - password: "postgres"; - database: "CarsDB"; - table: "Cars"; -}`; diff --git a/libs/extensions/rdbms/lang/src/lib/sqlite-loader-meta-information.ts b/libs/extensions/rdbms/lang/src/lib/sqlite-loader-meta-information.ts deleted file mode 100644 index 531d9fe2c..000000000 --- a/libs/extensions/rdbms/lang/src/lib/sqlite-loader-meta-information.ts +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - IOType, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; - -export class SQLiteLoaderMetaInformation extends BlockMetaInformation { - constructor() { - super( - 'SQLiteLoader', - { - table: { - type: PrimitiveValuetypes.Text, - docs: { - description: 'The name of the table to write into.', - }, - }, - file: { - type: PrimitiveValuetypes.Text, - docs: { - description: - 'The path to a SQLite file that will be created if it does not exist. Usual file extensions are `.sqlite` and `.db`.', - }, - }, - dropTable: { - type: PrimitiveValuetypes.Boolean, - defaultValue: true, - docs: { - description: - 'Indicates, whether to drop the table before loading data into it. If `false`, data is appended to the table instead of dropping it.', - }, - }, - }, - IOType.TABLE, - IOType.NONE, - ); - this.docs.description = 'Loads a `Table` into a SQLite database sink.'; - this.docs.examples = [ - { - code: blockExampleUsage, - description: - 'A SQLite file `cars.db` is created in the working directory. Incoming data is written to the table `cars`.', - }, - ]; - } -} - -const blockExampleUsage = `block CarsLoader oftype SQLiteLoader { - table: "cars"; - file: "./cars.db"; -}`; diff --git a/libs/extensions/rdbms/lang/tsconfig.json b/libs/extensions/rdbms/lang/tsconfig.json deleted file mode 100644 index 4022fd4d0..000000000 --- a/libs/extensions/rdbms/lang/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../../../../tsconfig.base.json", - "compilerOptions": { - "module": "commonjs", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" - } - ] -} diff --git a/libs/extensions/rdbms/lang/tsconfig.json.license b/libs/extensions/rdbms/lang/tsconfig.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/rdbms/lang/tsconfig.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/rdbms/lang/tsconfig.lib.json b/libs/extensions/rdbms/lang/tsconfig.lib.json deleted file mode 100644 index 18f2d37a1..000000000 --- a/libs/extensions/rdbms/lang/tsconfig.lib.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../../dist/out-tsc", - "declaration": true, - "types": ["node"] - }, - "include": ["src/**/*.ts"], - "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] -} diff --git a/libs/extensions/rdbms/lang/tsconfig.lib.json.license b/libs/extensions/rdbms/lang/tsconfig.lib.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/rdbms/lang/tsconfig.lib.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/rdbms/lang/tsconfig.spec.json b/libs/extensions/rdbms/lang/tsconfig.spec.json deleted file mode 100644 index 6668655fc..000000000 --- a/libs/extensions/rdbms/lang/tsconfig.spec.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "include": [ - "jest.config.ts", - "src/**/*.test.ts", - "src/**/*.spec.ts", - "src/**/*.d.ts" - ] -} diff --git a/libs/extensions/rdbms/lang/tsconfig.spec.json.license b/libs/extensions/rdbms/lang/tsconfig.spec.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/rdbms/lang/tsconfig.spec.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/std/lang/.babelrc b/libs/extensions/std/lang/.babelrc deleted file mode 100644 index e24a5465f..000000000 --- a/libs/extensions/std/lang/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@nrwl/web/babel", - { - "useBuiltIns": "usage" - } - ] - ] -} diff --git a/libs/extensions/std/lang/.babelrc.license b/libs/extensions/std/lang/.babelrc.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/std/lang/.babelrc.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/std/lang/.eslintrc.json b/libs/extensions/std/lang/.eslintrc.json deleted file mode 100644 index 632e9b0e2..000000000 --- a/libs/extensions/std/lang/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": ["../../../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} - }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/libs/extensions/std/lang/.eslintrc.json.license b/libs/extensions/std/lang/.eslintrc.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/std/lang/.eslintrc.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/std/lang/README.md b/libs/extensions/std/lang/README.md deleted file mode 100644 index e1798ab56..000000000 --- a/libs/extensions/std/lang/README.md +++ /dev/null @@ -1,17 +0,0 @@ - - -# extensions-std-lang - -This library was generated with [Nx](https://nx.dev). - -## Building - -Run `nx build extensions-std-lang` to build the library. - -## Running unit tests - -Run `nx test extensions-std-lang` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/extensions/std/lang/jest.config.ts b/libs/extensions/std/lang/jest.config.ts deleted file mode 100644 index 3c56c8520..000000000 --- a/libs/extensions/std/lang/jest.config.ts +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -export default { - displayName: 'extensions-std-lang', - preset: '../../../../jest.preset.js', - globals: { - 'ts-jest': { - tsconfig: '/tsconfig.spec.json', - }, - }, - transform: { - '^.+\\.[tj]s$': 'ts-jest', - }, - moduleFileExtensions: ['ts', 'js', 'html'], - coverageDirectory: '../../../../coverage/libs/extensions/std/lang', -}; diff --git a/libs/extensions/std/lang/package.json b/libs/extensions/std/lang/package.json deleted file mode 100644 index 53dfb5523..000000000 --- a/libs/extensions/std/lang/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "@jvalue/jayvee-extensions/std/lang", - "type": "commonjs" -} diff --git a/libs/extensions/std/lang/package.json.license b/libs/extensions/std/lang/package.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/std/lang/package.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/std/lang/project.json b/libs/extensions/std/lang/project.json deleted file mode 100644 index cf1faa3d6..000000000 --- a/libs/extensions/std/lang/project.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "extensions-std-lang", - "$schema": "../../../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "libs/extensions/std/lang/src", - "projectType": "library", - "targets": { - "build": { - "executor": "@nrwl/js:tsc", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/libs/extensions/std/lang", - "main": "libs/extensions/std/lang/src/index.ts", - "tsConfig": "libs/extensions/std/lang/tsconfig.lib.json", - "assets": ["libs/extensions/std/lang/*.md"] - } - }, - "lint": { - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["libs/extensions/std/lang/**/*.ts"] - } - }, - "test": { - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "libs/extensions/std/lang/jest.config.ts", - "passWithNoTests": false - } - } - }, - "tags": [] -} diff --git a/libs/extensions/std/lang/project.json.license b/libs/extensions/std/lang/project.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/std/lang/project.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/std/lang/src/archive-interpreter-meta-inf.ts b/libs/extensions/std/lang/src/archive-interpreter-meta-inf.ts deleted file mode 100644 index 7339fbd2a..000000000 --- a/libs/extensions/std/lang/src/archive-interpreter-meta-inf.ts +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - IOType, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; - -export class ArchiveInterpreterMetaInformation extends BlockMetaInformation { - constructor() { - super( - // How the block type should be called: - 'ArchiveInterpreter', - - // Property definitions: - { - archiveType: { - type: PrimitiveValuetypes.Text, - docs: { - description: - 'The archive type to be interpreted, e.g., "zip" or "gz".', - }, - }, - }, - // Input type: - IOType.FILE, - - // Output type: - IOType.FILE_SYSTEM, - ); - this.docs.description = - 'Interprets a `File` as an archive file and converts it to a `FileSystem`. The archive file root is considered the root of the `FileSystem`.'; - - this.docs.examples = [ - { - code: `block ZipArchiveInterpreter oftype ArchiveInterpreter { - archiveType: "zip"; -}`, - description: - 'Interprets a `File` as a ZIP-archive and creates a `FileSystem` of its extracted contents.', - }, - ]; - } -} diff --git a/libs/extensions/std/lang/src/example-validation.spec.ts b/libs/extensions/std/lang/src/example-validation.spec.ts deleted file mode 100644 index c98e468c4..000000000 --- a/libs/extensions/std/lang/src/example-validation.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { readdirSync } from 'fs'; -import * as path from 'path'; - -import { - JayveeServices, - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { StdLangExtension } from './extension'; - -describe('jv example tests', () => { - let services: JayveeServices; - let validate: (input: string) => Promise>; - - const baseDirPath = path.resolve(__dirname, '../../../../../example/'); - const readJvTestAsset = readJvTestAssetHelper(baseDirPath); - - beforeAll(() => { - // Register std extension - useExtension(new StdLangExtension()); - // Create language services - services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it.each( - // Get all .jv files from example dir - readdirSync(baseDirPath).filter((file) => path.extname(file) === '.jv'), - )('valid %s', async (file: string) => { - const text = readJvTestAsset(file); - - // Validate input - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - // Expect 0 errors - expect(diagnostics).toHaveLength(0); - }); -}); diff --git a/libs/extensions/std/lang/src/extension.ts b/libs/extensions/std/lang/src/extension.ts deleted file mode 100644 index 407dd38c9..000000000 --- a/libs/extensions/std/lang/src/extension.ts +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { RdbmsLangExtension } from '@jvalue/jayvee-extensions/rdbms/lang'; -import { TabularLangExtension } from '@jvalue/jayvee-extensions/tabular/lang'; -import { - BlockMetaInformation, - ConstructorClass, - JayveeLangExtension, -} from '@jvalue/jayvee-language-server'; - -import { ArchiveInterpreterMetaInformation } from './archive-interpreter-meta-inf'; -import { FilePickerMetaInformation } from './file-picker-meta-inf'; -import { GtfsRTInterpreterMetaInformation } from './gtfs-rt-interpreter-meta-inf'; -import { HttpExtractorMetaInformation } from './http-extractor-meta-inf'; -import { TextFileInterpreterMetaInformation } from './text-file-interpreter-meta-inf'; -import { TextLineDeleterMetaInformation } from './text-line-deleter-meta-inf'; -import { TextRangeSelectorMetaInformation } from './text-range-selector-meta-inf'; - -export class StdLangExtension implements JayveeLangExtension { - private readonly wrappedExtensions: JayveeLangExtension[] = [ - new TabularLangExtension(), - new RdbmsLangExtension(), - ]; - - getBlockMetaInf(): Array> { - return [ - ...this.wrappedExtensions.map((x) => x.getBlockMetaInf()).flat(), - HttpExtractorMetaInformation, - TextFileInterpreterMetaInformation, - TextRangeSelectorMetaInformation, - TextLineDeleterMetaInformation, - ArchiveInterpreterMetaInformation, - FilePickerMetaInformation, - GtfsRTInterpreterMetaInformation, - ]; - } -} diff --git a/libs/extensions/std/lang/src/file-picker-meta-inf.ts b/libs/extensions/std/lang/src/file-picker-meta-inf.ts deleted file mode 100644 index df53872bd..000000000 --- a/libs/extensions/std/lang/src/file-picker-meta-inf.ts +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - IOType, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; - -export class FilePickerMetaInformation extends BlockMetaInformation { - constructor() { - super( - // How the block type should be called: - 'FilePicker', - - // Property definitions: - { - path: { - type: PrimitiveValuetypes.Text, - docs: { - description: - 'The path of the file to select, relative to the root of the provided `FileSystem`.', - }, - }, - }, - // Input type: - IOType.FILE_SYSTEM, - - // Output type: - IOType.FILE, - ); - - this.docs.description = - 'Selects one `File` from a `FileSystem` based on its relative path to the root of the `FileSystem`. If no file matches the relative path, no output is created and the execution of the pipeline is aborted.'; - this.docs.examples = [ - { - code: `block AgencyFilePicker oftype FilePicker { - path: "./agency.txt"; -}`, - description: - 'Tries to pick the file `agency.txt` from the root of the provided `FileSystem`. If `agency.txt` exists it is passed on as `File`, if it does not exist the execution of the pipeline is aborted.', - }, - ]; - } -} diff --git a/libs/extensions/std/lang/src/gtfs-rt-interpreter-meta-inf.spec.ts b/libs/extensions/std/lang/src/gtfs-rt-interpreter-meta-inf.spec.ts deleted file mode 100644 index 9110e1635..000000000 --- a/libs/extensions/std/lang/src/gtfs-rt-interpreter-meta-inf.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - TestLangExtension, - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { StdLangExtension } from './extension'; - -describe('Validation of GtfsRTInterpreterMetaInformation', () => { - let validate: (input: string) => Promise>; - - const readJvTestAsset = readJvTestAssetHelper(__dirname, '../test/assets/'); - - beforeAll(() => { - // Register std extension - useExtension(new StdLangExtension()); - // Register test extension - useExtension(new TestLangExtension()); - // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it('should diagnose no error on valid entity parameter value', async () => { - const text = readJvTestAsset( - 'gtfs-rt-interpreter-meta-inf/valid-valid-entity-param.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - }); - - it('should diagnose error on invalid entity parameter value', async () => { - const text = readJvTestAsset( - 'gtfs-rt-interpreter-meta-inf/invalid-invalid-entity-param.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(1); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: 'Entity must be "trip_update", "alert" or "vehicle"', - }), - ]), - ); - }); -}); diff --git a/libs/extensions/std/lang/src/gtfs-rt-interpreter-meta-inf.ts b/libs/extensions/std/lang/src/gtfs-rt-interpreter-meta-inf.ts deleted file mode 100644 index 39e7cf32a..000000000 --- a/libs/extensions/std/lang/src/gtfs-rt-interpreter-meta-inf.ts +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - EvaluationContext, - IOType, - PrimitiveValuetypes, - PropertyAssignment, - ValidationContext, - evaluatePropertyValue, -} from '@jvalue/jayvee-language-server'; - -export class GtfsRTInterpreterMetaInformation extends BlockMetaInformation { - constructor() { - super( - // How the block type should be called: - 'GtfsRTInterpreter', - - // Attribute definitions: - { - entity: { - type: PrimitiveValuetypes.Text, - validation: isGtfsRTEntity, - docs: { - description: `Entity to process from GTFS-RT-feed (\`trip_update\`, \`alert\` or \`vehicle\`). - We currently support following Output-Sheets, each are an equivalent to the flattened Element Index defined in (just required fields are included)): - - Entity TripUpdate: - \`\`\` - [ - 'header.gtfs_realtime_version', - 'header.timestamp', - 'header.incrementality', - 'entity.id', - 'entity.trip_update.trip.trip_id', - 'entity.trip_update.trip.route_id', - 'entity.trip_update.stop_time_update.stop_sequence', - 'entity.trip_update.stop_time_update.stop_id', - 'entity.trip_update.stop_time_update.arrival.time', - 'entity.trip_update.stop_time_update.departure.time', - ]; - - \`\`\` - Entity VehiclePosition: - \`\`\` - [ - 'header.gtfs_realtime_version', - 'header.timestamp', - 'header.incrementality', - 'entity.id', - 'entity.vehicle_position.vehicle_descriptor.id', - 'entity.vehicle_position.trip.trip_id', - 'entity.vehicle_position.trip.route_id', - 'entity.vehicle_position.position.latitude', - 'entity.vehicle_position.position.longitude', - 'entity.vehicle_position.timestamp', - ]; - \`\`\` - - Entity Alert: - \`\`\` - [ - 'header.gtfs_realtime_version', - 'header.timestamp', - 'header.incrementality', - 'entity.id', - 'entity.alert.informed_entity.route_id', - 'entity.alert.header_text', - 'entity.alert.description_text', - ]; - \`\`\` - - `, - }, - }, - }, - // Input type: - IOType.FILE, - - // Output type: - IOType.SHEET, - ); - this.docs.description = - 'Interprets an protobuf file (binary) of type `File` by decoding the file according to `gtfs-realtime.proto`. Outputs the extracted entity defined by `entity` as a `Sheet`'; - this.docs.examples = [ - { - code: blockExampleUsage, - description: - 'A file is interpretet as an GTFS-RT file, which contains TripUpdate.', - }, - ]; - } -} - -const blockExampleUsage = `block GtfsRTTripUpdateInterpreter oftype GtfsRTInterpreter{ - entity: "trip_update"; -}`; - -function isGtfsRTEntity( - property: PropertyAssignment, - validationContext: ValidationContext, - evaluationContext: EvaluationContext, -) { - const entityValue = evaluatePropertyValue( - property, - evaluationContext, - PrimitiveValuetypes.Text, - ); - if (entityValue === undefined) { - return; - } - - if (!['trip_update', 'alert', 'vehicle'].includes(entityValue)) { - validationContext.accept( - 'error', - `Entity must be "trip_update", "alert" or "vehicle"`, - { - node: property.value, - }, - ); - } -} diff --git a/libs/extensions/std/lang/src/http-extractor-meta-inf.ts b/libs/extensions/std/lang/src/http-extractor-meta-inf.ts deleted file mode 100644 index 1ac27dc34..000000000 --- a/libs/extensions/std/lang/src/http-extractor-meta-inf.ts +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - IOType, - PrimitiveValuetypes, - evaluatePropertyValue, -} from '@jvalue/jayvee-language-server'; - -export class HttpExtractorMetaInformation extends BlockMetaInformation { - constructor() { - super( - // How the block type should be called: - 'HttpExtractor', - - // Property definitions: - { - url: { - type: PrimitiveValuetypes.Text, - docs: { - description: 'The URL to the file in the web to extract.', - examples: [ - { - code: 'url: "tinyurl.com/4ub9spwz"', - description: 'Specifies the URL to fetch the data from.', - }, - ], - }, - }, - retries: { - type: PrimitiveValuetypes.Integer, - defaultValue: 0, - docs: { - description: - 'Configures how many retries should be executed after a failure fetching the data.', - examples: [ - { - code: 'retries: 3', - description: - 'Executes up to 3 retries if the original retry fails (so in total max. 4 requests).', - }, - ], - }, - validation: (property, validationContext, evaluationContext) => { - const encodingValue = evaluatePropertyValue( - property, - evaluationContext, - PrimitiveValuetypes.Integer, - ); - if (encodingValue === undefined) { - return; - } - - if (encodingValue < 0) { - validationContext.accept( - 'error', - 'Only not negative integers allowed', - { - node: property, - property: 'value', - }, - ); - } - }, - }, - retryBackoffMilliseconds: { - type: PrimitiveValuetypes.Integer, - defaultValue: 2000, - docs: { - description: - 'Configures the wait time in milliseconds before executing a retry.', - examples: [ - { - code: 'retryBackoff: 5000', - description: 'Waits 5s (5000 ms) before executing a retry.', - }, - ], - }, - validation: (property, validationContext, evaluationContext) => { - const minBockoffValue = 1000; - - const encodingValue = evaluatePropertyValue( - property, - evaluationContext, - PrimitiveValuetypes.Integer, - ); - if (encodingValue === undefined) { - return; - } - - if (encodingValue < minBockoffValue) { - validationContext.accept( - 'error', - `Only integers larger or equal to ${minBockoffValue} are allowed`, - { - node: property, - property: 'value', - }, - ); - } - }, - }, - retryBackoffStrategy: { - type: PrimitiveValuetypes.Text, - defaultValue: 'exponential', - docs: { - description: - 'Configures the wait strategy before executing a retry. Can have values "exponential" or "linear".', - examples: [ - { - code: 'retryBackoffStrategy: "linear"', - description: - 'Waits always the same amount of time before executing a retry.', - }, - { - code: 'retryBackoffStrategy: "exponential"', - description: - 'Exponentially increases the wait time before executing a retry.', - }, - ], - }, - validation: (property, validationContext, evaluationContext) => { - const allowedValues = ['exponential', 'linear']; - - const encodingValue = evaluatePropertyValue( - property, - evaluationContext, - PrimitiveValuetypes.Text, - ); - if (encodingValue === undefined) { - return; - } - - if (!allowedValues.includes(encodingValue)) { - validationContext.accept( - 'error', - `Only the following values are allowed: ${allowedValues - .map((v) => `"${v}"`) - .join(', ')}`, - { - node: property, - property: 'value', - }, - ); - } - }, - }, - followRedirects: { - type: PrimitiveValuetypes.Boolean, - defaultValue: true, - docs: { - description: - 'Indicates, whether to follow redirects on get requests. If `false`, redirects are not followed. Default `true`', - examples: [ - { - code: 'url: "tinyurl.com/4ub9spwz" \n followRedirects: true', - description: - 'Specifies the URL to fetch the data from and allows redirects.', - }, - ], - }, - }, - }, - - // Input type: - IOType.NONE, - - // Output type: - IOType.FILE, - ); - this.docs.description = 'Extracts a `File` from the web.'; - this.docs.examples = [ - { - code: blockExampleUsage, - description: 'Fetches a file from the given URL.', - }, - ]; - } -} - -const blockExampleUsage = `block CarsFileExtractor oftype HttpExtractor { - url: "tinyurl.com/4ub9spwz"; -}`; diff --git a/libs/extensions/std/lang/src/index.ts b/libs/extensions/std/lang/src/index.ts deleted file mode 100644 index 88d3a0045..000000000 --- a/libs/extensions/std/lang/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -export * from './extension'; diff --git a/libs/extensions/std/lang/src/meta-inf-example-validation.spec.ts b/libs/extensions/std/lang/src/meta-inf-example-validation.spec.ts deleted file mode 100644 index 26a7cd554..000000000 --- a/libs/extensions/std/lang/src/meta-inf-example-validation.spec.ts +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockDefinition, - BlockMetaInformation, - IOType, - JayveeServices, - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - ParseHelperOptions, - TestLangExtension, - ValidationResult, - expectNoParserAndLexerErrors, - getTestExtensionBlockForIOType, - parseHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode, AstNodeLocator, LangiumDocument } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { StdLangExtension } from './extension'; - -describe('Validation of builtin examples of BlockMetaInformation', () => { - let services: JayveeServices; - let parse: ( - input: string, - options?: ParseHelperOptions, - ) => Promise>; - let validate: (input: string) => Promise>; - - let locator: AstNodeLocator; - - const testExtension = new TestLangExtension(); - const stdExtension = new StdLangExtension(); - - function generateBlockWithPipeForIOType( - io: IOType, - ioType: 'input' | 'output', - blockName: string, - ): string { - const ioBlockMetaInf = getTestExtensionBlockForIOType( - testExtension, - io, - ioType, - ); - // Generate block - const ioBlockName = - ioType === 'input' ? 'TestLoaderBlock' : 'TestExtractorBlock'; - const ioBlock = `block ${ioBlockName} oftype ${ioBlockMetaInf.type} {}`; - // generate pipe - const pipe = - ioType === 'input' - ? `${blockName} -> ${ioBlockName};` - : `${ioBlockName} -> ${blockName};`; - return `\n${ioBlock}\n${pipe}`; - } - - async function getBlockNameFromExample( - blockExample: string, - ): Promise { - const parsedExample = await parse(`pipeline Test {${blockExample}}`); - expectNoParserAndLexerErrors(parsedExample); - return ( - locator.getAstNode( - parsedExample.parseResult.value, - 'pipelines@0/blocks@0', - ) as BlockDefinition - ).name; - } - - async function generateFullJvExample( - blockMetaInf: BlockMetaInformation, - blockExample: string, - ): Promise { - const blockName = await getBlockNameFromExample(blockExample); - - let pipelineContent = `${blockExample}`; - // Generate extractor block and pipe - if (blockMetaInf.hasInput()) { - pipelineContent += generateBlockWithPipeForIOType( - blockMetaInf.inputType, - 'output', - blockName, - ); - } - // Generate loader block and pipe - if (blockMetaInf.hasOutput()) { - pipelineContent += generateBlockWithPipeForIOType( - blockMetaInf.outputType, - 'input', - blockName, - ); - } - return `pipeline Test { - ${pipelineContent} - }`; - } - - beforeAll(() => { - // Register test extension - useExtension(testExtension); - // Register std extension - useExtension(stdExtension); - // Create language services - services = createJayveeServices(NodeFileSystem).Jayvee; - locator = services.workspace.AstNodeLocator; - // Create validation helper for language services - validate = validationHelper(services); - // Parse function for Jayvee (without validation) - parse = parseHelper(services); - }); - - it.each( - stdExtension.getBlockMetaInf().map((metaInfClass) => { - const metaInf = new metaInfClass(); - return [metaInf.type, metaInf]; - }), - )( - 'should have no error on %s example validation', - async (type, blockMetaInf) => { - for (const example of blockMetaInf.docs.examples ?? []) { - const text = await generateFullJvExample(blockMetaInf, example.code); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - } - }, - ); -}); diff --git a/libs/extensions/std/lang/src/text-file-interpreter-meta-inf.spec.ts b/libs/extensions/std/lang/src/text-file-interpreter-meta-inf.spec.ts deleted file mode 100644 index 60c7fbd4d..000000000 --- a/libs/extensions/std/lang/src/text-file-interpreter-meta-inf.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - TestLangExtension, - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { StdLangExtension } from './extension'; - -describe('Validation of TextFileInterpreterMetaInformation', () => { - let validate: (input: string) => Promise>; - - const readJvTestAsset = readJvTestAssetHelper(__dirname, '../test/assets/'); - - beforeAll(() => { - // Register std extension - useExtension(new StdLangExtension()); - // Register test extension - useExtension(new TestLangExtension()); - // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it('should diagnose error on invalid encoding parameter value', async () => { - const text = readJvTestAsset( - 'text-file-interpreter-meta-inf/invalid-invalid-encoding-param.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(1); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: 'Unknown encoding "invalid"', - }), - ]), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'text-file-interpreter-meta-inf/valid-utf8-encoding.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - }); -}); diff --git a/libs/extensions/std/lang/src/text-file-interpreter-meta-inf.ts b/libs/extensions/std/lang/src/text-file-interpreter-meta-inf.ts deleted file mode 100644 index c5789ba78..000000000 --- a/libs/extensions/std/lang/src/text-file-interpreter-meta-inf.ts +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { TextDecoder } from 'util'; - -import { - BlockMetaInformation, - IOType, - PrimitiveValuetypes, - evaluatePropertyValue, -} from '@jvalue/jayvee-language-server'; - -export class TextFileInterpreterMetaInformation extends BlockMetaInformation { - constructor() { - super( - 'TextFileInterpreter', - { - encoding: { - type: PrimitiveValuetypes.Text, - defaultValue: 'utf-8', - docs: { - description: 'The encoding used for decoding the file contents.', - }, - validation: (property, validationContext, evaluationContext) => { - const encodingValue = evaluatePropertyValue( - property, - evaluationContext, - PrimitiveValuetypes.Text, - ); - if (encodingValue === undefined) { - return; - } - - try { - new TextDecoder(encodingValue); - } catch (error) { - validationContext.accept( - 'error', - `Unknown encoding "${encodingValue}"`, - { - node: property.value, - }, - ); - } - }, - }, - lineBreak: { - type: PrimitiveValuetypes.Regex, - defaultValue: /\r?\n/, - docs: { - description: 'The regex for identifying line breaks.', - }, - }, - }, - // Input type: - IOType.FILE, - - // Output type: - IOType.TEXT_FILE, - ); - this.docs.description = 'Interprets a `File` as a `TextFile`.'; - } -} diff --git a/libs/extensions/std/lang/src/text-line-deleter-meta-inf.spec.ts b/libs/extensions/std/lang/src/text-line-deleter-meta-inf.spec.ts deleted file mode 100644 index eeacaf4e2..000000000 --- a/libs/extensions/std/lang/src/text-line-deleter-meta-inf.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - TestLangExtension, - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { StdLangExtension } from './extension'; - -describe('Validation of TextLineDeleterMetaInformation', () => { - let validate: (input: string) => Promise>; - - const readJvTestAsset = readJvTestAssetHelper(__dirname, '../test/assets/'); - - beforeAll(() => { - // Register std extension - useExtension(new StdLangExtension()); - // Register test extension - useExtension(new TestLangExtension()); - // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it('should diagnose error on line parameter less or equal to zero', async () => { - const text = readJvTestAsset( - 'text-line-deleter-meta-inf/invalid-line-less-or-equal-zero.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(3); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: 'Line numbers need to be greater than zero', - }), - ]), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'text-line-deleter-meta-inf/valid-postive-line-number.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - }); -}); diff --git a/libs/extensions/std/lang/src/text-line-deleter-meta-inf.ts b/libs/extensions/std/lang/src/text-line-deleter-meta-inf.ts deleted file mode 100644 index 2f36d3078..000000000 --- a/libs/extensions/std/lang/src/text-line-deleter-meta-inf.ts +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - CollectionValuetype, - IOType, - PrimitiveValuetypes, - evaluatePropertyValue, -} from '@jvalue/jayvee-language-server'; - -export class TextLineDeleterMetaInformation extends BlockMetaInformation { - constructor() { - super( - 'TextLineDeleter', - { - lines: { - type: new CollectionValuetype(PrimitiveValuetypes.Integer), - validation: (property, validationContext, evaluationContext) => { - const lines = evaluatePropertyValue( - property, - evaluationContext, - new CollectionValuetype(PrimitiveValuetypes.Integer), - ); - lines?.forEach((value, index) => { - if (value <= 0) { - validationContext.accept( - 'error', - `Line numbers need to be greater than zero`, - { - node: property.value, - property: 'values', - index: index, - }, - ); - } - }); - }, - docs: { - description: 'The line numbers to delete.', - }, - }, - }, - // Input type: - IOType.TEXT_FILE, - - // Output type: - IOType.TEXT_FILE, - ); - this.docs.description = 'Deletes individual lines from a `TextFile`.'; - } -} diff --git a/libs/extensions/std/lang/src/text-range-selector-meta-inf.spec.ts b/libs/extensions/std/lang/src/text-range-selector-meta-inf.spec.ts deleted file mode 100644 index d0fdd645d..000000000 --- a/libs/extensions/std/lang/src/text-range-selector-meta-inf.spec.ts +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - TestLangExtension, - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { StdLangExtension } from './extension'; - -describe('Validation of TextRangeSelectorMetaInformation', () => { - let validate: (input: string) => Promise>; - - const readJvTestAsset = readJvTestAssetHelper(__dirname, '../test/assets/'); - - beforeAll(() => { - // Register std extension - useExtension(new StdLangExtension()); - // Register test extension - useExtension(new TestLangExtension()); - // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it('should diagnose error on lineFrom parameter less or equal to zero', async () => { - const text = readJvTestAsset( - 'text-range-selector-meta-inf/invalid-lineFrom-less-or-equal-zero.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(1); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: 'Line numbers need to be greater than zero', - }), - ]), - ); - }); - - it('should diagnose error on lineTo parameter less or equal to zero', async () => { - const text = readJvTestAsset( - 'text-range-selector-meta-inf/invalid-lineTo-less-or-equal-zero.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(2); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: 'Line numbers need to be greater than zero', - }), - ]), - ); - }); - - it('should diagnose error on lineFrom > lineTo', async () => { - const text = readJvTestAsset( - 'text-range-selector-meta-inf/invalid-lineFrom-greater-lineTo.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(2); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: - 'The lower line number needs to be smaller or equal to the upper line number', - }), - ]), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'text-range-selector-meta-inf/valid-correct-range.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - }); -}); diff --git a/libs/extensions/std/lang/src/text-range-selector-meta-inf.ts b/libs/extensions/std/lang/src/text-range-selector-meta-inf.ts deleted file mode 100644 index 80a618cc8..000000000 --- a/libs/extensions/std/lang/src/text-range-selector-meta-inf.ts +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - EvaluationContext, - IOType, - PrimitiveValuetypes, - PropertyAssignment, - ValidationContext, - evaluatePropertyValue, -} from '@jvalue/jayvee-language-server'; - -export class TextRangeSelectorMetaInformation extends BlockMetaInformation { - constructor() { - super( - 'TextRangeSelector', - { - lineFrom: { - type: PrimitiveValuetypes.Integer, - defaultValue: 1, - validation: greaterThanZeroValidation, - }, - lineTo: { - type: PrimitiveValuetypes.Integer, - defaultValue: Number.POSITIVE_INFINITY, - validation: greaterThanZeroValidation, - }, - }, - // Input type: - IOType.TEXT_FILE, - - // Output type: - IOType.TEXT_FILE, - - (propertyBody, validationContext, evaluationContext) => { - const lineFromProperty = propertyBody.properties.find( - (p) => p.name === 'lineFrom', - ); - const lineToProperty = propertyBody.properties.find( - (p) => p.name === 'lineTo', - ); - - if (lineFromProperty === undefined || lineToProperty === undefined) { - return; - } - - const lineFrom = evaluatePropertyValue( - lineFromProperty, - evaluationContext, - PrimitiveValuetypes.Integer, - ); - const lineTo = evaluatePropertyValue( - lineToProperty, - evaluationContext, - PrimitiveValuetypes.Integer, - ); - if (lineFrom === undefined || lineTo === undefined) { - return; - } - - if (lineFrom > lineTo) { - [lineFromProperty, lineToProperty].forEach((property) => { - validationContext.accept( - 'error', - 'The lower line number needs to be smaller or equal to the upper line number', - { node: property.value }, - ); - }); - } - }, - ); - this.docs.description = 'Selects a range of lines from a `TextFile`.'; - } -} - -function greaterThanZeroValidation( - property: PropertyAssignment, - validationContext: ValidationContext, - evaluationContext: EvaluationContext, -) { - const value = evaluatePropertyValue( - property, - evaluationContext, - PrimitiveValuetypes.Integer, - ); - if (value === undefined) { - return; - } - - if (value <= 0) { - validationContext.accept( - 'error', - `Line numbers need to be greater than zero`, - { - node: property.value, - }, - ); - } -} diff --git a/libs/extensions/std/lang/test/assets/gtfs-rt-interpreter-meta-inf/invalid-invalid-entity-param.jv b/libs/extensions/std/lang/test/assets/gtfs-rt-interpreter-meta-inf/invalid-invalid-entity-param.jv deleted file mode 100644 index abcdd2705..000000000 --- a/libs/extensions/std/lang/test/assets/gtfs-rt-interpreter-meta-inf/invalid-invalid-entity-param.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype GtfsRTInterpreter { - entity: 'invalid'; - } - - block TestExtractor oftype TestFileExtractor { - } - - block TestLoader oftype TestSheetLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/std/lang/test/assets/gtfs-rt-interpreter-meta-inf/valid-valid-entity-param.jv b/libs/extensions/std/lang/test/assets/gtfs-rt-interpreter-meta-inf/valid-valid-entity-param.jv deleted file mode 100644 index 98acd3a98..000000000 --- a/libs/extensions/std/lang/test/assets/gtfs-rt-interpreter-meta-inf/valid-valid-entity-param.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype GtfsRTInterpreter { - entity: 'alert'; - } - - block TestExtractor oftype TestFileExtractor { - } - - block TestLoader oftype TestSheetLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/std/lang/test/assets/text-file-interpreter-meta-inf/invalid-invalid-encoding-param.jv b/libs/extensions/std/lang/test/assets/text-file-interpreter-meta-inf/invalid-invalid-encoding-param.jv deleted file mode 100644 index 4a9dbe87b..000000000 --- a/libs/extensions/std/lang/test/assets/text-file-interpreter-meta-inf/invalid-invalid-encoding-param.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype TextFileInterpreter { - encoding: 'invalid'; - } - - block TestExtractor oftype TestFileExtractor { - } - - block TestLoader oftype TestTextFileLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/std/lang/test/assets/text-file-interpreter-meta-inf/valid-utf8-encoding.jv b/libs/extensions/std/lang/test/assets/text-file-interpreter-meta-inf/valid-utf8-encoding.jv deleted file mode 100644 index 7537150f1..000000000 --- a/libs/extensions/std/lang/test/assets/text-file-interpreter-meta-inf/valid-utf8-encoding.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype TextFileInterpreter { - encoding: 'utf8'; - } - - block TestExtractor oftype TestFileExtractor { - } - - block TestLoader oftype TestTextFileLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/std/lang/test/assets/text-line-deleter-meta-inf/invalid-line-less-or-equal-zero.jv b/libs/extensions/std/lang/test/assets/text-line-deleter-meta-inf/invalid-line-less-or-equal-zero.jv deleted file mode 100644 index 68f2df265..000000000 --- a/libs/extensions/std/lang/test/assets/text-line-deleter-meta-inf/invalid-line-less-or-equal-zero.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype TextLineDeleter { - lines: [2,3,0,-1,-20]; - } - - block TestExtractor oftype TestTextFileExtractor { - } - - block TestLoader oftype TestTextFileLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/std/lang/test/assets/text-line-deleter-meta-inf/valid-postive-line-number.jv b/libs/extensions/std/lang/test/assets/text-line-deleter-meta-inf/valid-postive-line-number.jv deleted file mode 100644 index fc7709419..000000000 --- a/libs/extensions/std/lang/test/assets/text-line-deleter-meta-inf/valid-postive-line-number.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype TextLineDeleter { - lines: [2,3]; - } - - block TestExtractor oftype TestTextFileExtractor { - } - - block TestLoader oftype TestTextFileLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineFrom-greater-lineTo.jv b/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineFrom-greater-lineTo.jv deleted file mode 100644 index cdd0a588c..000000000 --- a/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineFrom-greater-lineTo.jv +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype TextRangeSelector { - lineFrom: 10; - lineTo: 1; - } - - block TestExtractor oftype TestTextFileExtractor { - } - - block TestLoader oftype TestTextFileLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineFrom-less-or-equal-zero.jv b/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineFrom-less-or-equal-zero.jv deleted file mode 100644 index 6bce31112..000000000 --- a/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineFrom-less-or-equal-zero.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype TextRangeSelector { - lineFrom: -1; - } - - block TestExtractor oftype TestTextFileExtractor { - } - - block TestLoader oftype TestTextFileLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineTo-less-or-equal-zero.jv b/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineTo-less-or-equal-zero.jv deleted file mode 100644 index bcb03507e..000000000 --- a/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/invalid-lineTo-less-or-equal-zero.jv +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype TextRangeSelector { - lineFrom: -2; - lineTo: -1; - } - - block TestExtractor oftype TestTextFileExtractor { - } - - block TestLoader oftype TestTextFileLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/valid-correct-range.jv b/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/valid-correct-range.jv deleted file mode 100644 index 3359596c0..000000000 --- a/libs/extensions/std/lang/test/assets/text-range-selector-meta-inf/valid-correct-range.jv +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype TextRangeSelector { - lineFrom: 1; - lineTo: 2; - } - - block TestExtractor oftype TestTextFileExtractor { - } - - block TestLoader oftype TestTextFileLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/std/lang/tsconfig.json b/libs/extensions/std/lang/tsconfig.json deleted file mode 100644 index 4022fd4d0..000000000 --- a/libs/extensions/std/lang/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../../../../tsconfig.base.json", - "compilerOptions": { - "module": "commonjs", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" - } - ] -} diff --git a/libs/extensions/std/lang/tsconfig.json.license b/libs/extensions/std/lang/tsconfig.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/std/lang/tsconfig.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/std/lang/tsconfig.lib.json b/libs/extensions/std/lang/tsconfig.lib.json deleted file mode 100644 index 18f2d37a1..000000000 --- a/libs/extensions/std/lang/tsconfig.lib.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../../dist/out-tsc", - "declaration": true, - "types": ["node"] - }, - "include": ["src/**/*.ts"], - "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] -} diff --git a/libs/extensions/std/lang/tsconfig.lib.json.license b/libs/extensions/std/lang/tsconfig.lib.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/std/lang/tsconfig.lib.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/std/lang/tsconfig.spec.json b/libs/extensions/std/lang/tsconfig.spec.json deleted file mode 100644 index 6668655fc..000000000 --- a/libs/extensions/std/lang/tsconfig.spec.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "include": [ - "jest.config.ts", - "src/**/*.test.ts", - "src/**/*.spec.ts", - "src/**/*.d.ts" - ] -} diff --git a/libs/extensions/std/lang/tsconfig.spec.json.license b/libs/extensions/std/lang/tsconfig.spec.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/std/lang/tsconfig.spec.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/tabular/lang/.babelrc b/libs/extensions/tabular/lang/.babelrc deleted file mode 100644 index e24a5465f..000000000 --- a/libs/extensions/tabular/lang/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@nrwl/web/babel", - { - "useBuiltIns": "usage" - } - ] - ] -} diff --git a/libs/extensions/tabular/lang/.babelrc.license b/libs/extensions/tabular/lang/.babelrc.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/tabular/lang/.babelrc.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/tabular/lang/.eslintrc.json b/libs/extensions/tabular/lang/.eslintrc.json deleted file mode 100644 index 632e9b0e2..000000000 --- a/libs/extensions/tabular/lang/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": ["../../../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} - }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/libs/extensions/tabular/lang/.eslintrc.json.license b/libs/extensions/tabular/lang/.eslintrc.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/tabular/lang/.eslintrc.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/tabular/lang/README.md b/libs/extensions/tabular/lang/README.md deleted file mode 100644 index da66460c6..000000000 --- a/libs/extensions/tabular/lang/README.md +++ /dev/null @@ -1,17 +0,0 @@ - - -# extensions-tabular-lang - -This library was generated with [Nx](https://nx.dev). - -## Building - -Run `nx build extensions-tabular-lang` to build the library. - -## Running unit tests - -Run `nx test extensions-tabular-lang` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/extensions/tabular/lang/jest.config.ts b/libs/extensions/tabular/lang/jest.config.ts deleted file mode 100644 index bdeda4338..000000000 --- a/libs/extensions/tabular/lang/jest.config.ts +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -export default { - displayName: 'extensions-tabular-lang', - preset: '../../../../jest.preset.js', - globals: { - 'ts-jest': { - tsconfig: '/tsconfig.spec.json', - }, - }, - transform: { - '^.+\\.[tj]s$': 'ts-jest', - }, - moduleFileExtensions: ['ts', 'js', 'html'], - coverageDirectory: '../../../../coverage/libs/extensions/tabular/lang', -}; diff --git a/libs/extensions/tabular/lang/package.json b/libs/extensions/tabular/lang/package.json deleted file mode 100644 index 1c495c53a..000000000 --- a/libs/extensions/tabular/lang/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "@jvalue/jayvee-extensions/tabular/lang", - "type": "commonjs" -} diff --git a/libs/extensions/tabular/lang/package.json.license b/libs/extensions/tabular/lang/package.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/tabular/lang/package.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/tabular/lang/project.json b/libs/extensions/tabular/lang/project.json deleted file mode 100644 index 287c6e5ce..000000000 --- a/libs/extensions/tabular/lang/project.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "extensions-tabular-lang", - "$schema": "../../../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "libs/extensions/tabular/lang/src", - "projectType": "library", - "targets": { - "build": { - "executor": "@nrwl/js:tsc", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/libs/extensions/tabular/lang", - "main": "libs/extensions/tabular/lang/src/index.ts", - "tsConfig": "libs/extensions/tabular/lang/tsconfig.lib.json", - "assets": ["libs/extensions/tabular/lang/*.md"] - } - }, - "lint": { - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["libs/extensions/tabular/lang/**/*.ts"] - } - }, - "test": { - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "libs/extensions/tabular/lang/jest.config.ts", - "passWithNoTests": false - } - } - }, - "tags": [] -} diff --git a/libs/extensions/tabular/lang/project.json.license b/libs/extensions/tabular/lang/project.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/tabular/lang/project.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/tabular/lang/src/extension.ts b/libs/extensions/tabular/lang/src/extension.ts deleted file mode 100644 index 959be5362..000000000 --- a/libs/extensions/tabular/lang/src/extension.ts +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - ConstructorClass, - JayveeLangExtension, -} from '@jvalue/jayvee-language-server'; - -import { CellRangeSelectorMetaInformation } from './lib/cell-range-selector-meta-inf'; -import { CellWriterMetaInformation } from './lib/cell-writer-meta-inf'; -import { ColumnDeleterMetaInformation } from './lib/column-deleter-meta-inf'; -import { CSVInterpreterMetaInformation } from './lib/csv-interpreter-meta-inf'; -import { RowDeleterMetaInformation } from './lib/row-deleter-meta-inf'; -import { SheetPickerMetaInformation } from './lib/sheet-picker-meta-inf'; -import { TableInterpreterMetaInformation } from './lib/table-interpreter-meta-inf'; -import { TableTransformerMetaInformation } from './lib/table-transformer-meta-inf'; -import { XLSXInterpreterMetaInformation } from './lib/xlsx-interpreter-meta-inf'; - -export class TabularLangExtension implements JayveeLangExtension { - getBlockMetaInf(): Array> { - return [ - ColumnDeleterMetaInformation, - RowDeleterMetaInformation, - CellRangeSelectorMetaInformation, - CellWriterMetaInformation, - TableInterpreterMetaInformation, - CSVInterpreterMetaInformation, - TableTransformerMetaInformation, - XLSXInterpreterMetaInformation, - SheetPickerMetaInformation, - ]; - } -} diff --git a/libs/extensions/tabular/lang/src/index.ts b/libs/extensions/tabular/lang/src/index.ts deleted file mode 100644 index 88d3a0045..000000000 --- a/libs/extensions/tabular/lang/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -export * from './extension'; diff --git a/libs/extensions/tabular/lang/src/lib/cell-range-selector-meta-inf.ts b/libs/extensions/tabular/lang/src/lib/cell-range-selector-meta-inf.ts deleted file mode 100644 index fc732c994..000000000 --- a/libs/extensions/tabular/lang/src/lib/cell-range-selector-meta-inf.ts +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - IOType, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; - -export class CellRangeSelectorMetaInformation extends BlockMetaInformation { - constructor() { - super( - 'CellRangeSelector', - { - select: { - type: PrimitiveValuetypes.CellRange, - docs: { - description: 'The cell range to select.', - examples: [ - { - code: 'select: range A1:E*', - description: - 'Select cells from `A1` to the last cell of column `E`.', - }, - ], - }, - }, - }, - IOType.SHEET, - IOType.SHEET, - ); - this.docs.description = - 'Selects a subset of a `Sheet` to produce a new `Sheet`.'; - this.docs.examples = [ - { - code: blockExample, - description: - 'Selects the cells in the given range and produces a new `Sheet` containing only the selected cells.', - }, - ]; - } -} - -const blockExample = `block CarsCoreDataSelector oftype CellRangeSelector { - select: range A1:E*; -}`; diff --git a/libs/extensions/tabular/lang/src/lib/cell-writer-meta-inf.spec.ts b/libs/extensions/tabular/lang/src/lib/cell-writer-meta-inf.spec.ts deleted file mode 100644 index 10413f0b8..000000000 --- a/libs/extensions/tabular/lang/src/lib/cell-writer-meta-inf.spec.ts +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - TestLangExtension, - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { TabularLangExtension } from '../extension'; - -describe('Validation of CellWriterMetaInformation', () => { - let validate: (input: string) => Promise>; - - const readJvTestAsset = readJvTestAssetHelper( - __dirname, - '../../test/assets/', - ); - - beforeAll(() => { - // Register std extension - useExtension(new TabularLangExtension()); - // Register test extension - useExtension(new TestLangExtension()); - // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it('should diagnose error on wrong dimension for at parameter', async () => { - const text = readJvTestAsset( - 'cell-writer-meta-inf/invalid-wrong-at-dimension.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(1); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: 'The cell range needs to be one-dimensional', - }), - ]), - ); - }); - - it('should diagnose error on number of write values does not match cell range', async () => { - const text = readJvTestAsset( - 'cell-writer-meta-inf/invalid-write-length-does-not-match-cell-range.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(2); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: - 'The number of values to write (3) does not match the number of cells (4)', - }), - expect.objectContaining({ - message: - 'The number of values to write (3) does not match the number of cells (4)', - }), - ]), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'cell-writer-meta-inf/valid-range-matches-array-length.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - }); -}); diff --git a/libs/extensions/tabular/lang/src/lib/cell-writer-meta-inf.ts b/libs/extensions/tabular/lang/src/lib/cell-writer-meta-inf.ts deleted file mode 100644 index 04cadb699..000000000 --- a/libs/extensions/tabular/lang/src/lib/cell-writer-meta-inf.ts +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - CollectionValuetype, - IOType, - PrimitiveValuetypes, - evaluatePropertyValue, -} from '@jvalue/jayvee-language-server'; - -export class CellWriterMetaInformation extends BlockMetaInformation { - constructor() { - super( - 'CellWriter', - { - write: { - type: new CollectionValuetype(PrimitiveValuetypes.Text), - docs: { - description: 'The values to write.', - examples: [ - { - code: 'write: ["Name"]', - description: 'Write the value "Name" into the cell.', - }, - { - code: 'write: ["Name1", "Name2"]', - description: - 'Write the value "Name1" into the first cell and "Name2 into the second.', - }, - ], - }, - }, - at: { - type: PrimitiveValuetypes.CellRange, - validation: (property, validationContext, evaluationContext) => { - const cellRange = evaluatePropertyValue( - property, - evaluationContext, - PrimitiveValuetypes.CellRange, - ); - if (cellRange === undefined) { - return; - } - - if (!cellRange.isOneDimensional()) { - validationContext.accept( - 'error', - 'The cell range needs to be one-dimensional', - { - node: cellRange.astNode, - }, - ); - } - }, - docs: { - description: 'The cells to write into.', - examples: [ - { - code: 'at: cell A1', - description: 'Write into cell A1.', - }, - { - code: 'at: range A1:A3', - description: 'Write into cells A1, A2 and A3.', - }, - ], - validation: 'Needs to be a one-dimensional range of cells.', - }, - }, - }, - IOType.SHEET, - IOType.SHEET, - (propertyBody, validationContext, evaluationContext) => { - const writeProperty = propertyBody.properties.find( - (p) => p.name === 'write', - ); - const atProperty = propertyBody.properties.find((p) => p.name === 'at'); - - if (writeProperty === undefined || atProperty === undefined) { - return; - } - - const writeValues = evaluatePropertyValue( - writeProperty, - evaluationContext, - new CollectionValuetype(PrimitiveValuetypes.Text), - ); - - const atValue = evaluatePropertyValue( - atProperty, - evaluationContext, - PrimitiveValuetypes.CellRange, - ); - - if (writeValues === undefined || atValue === undefined) { - return; - } - - const numberOfValuesToWrite = writeValues.length; - const numberOfCells = atValue.numberOfCells(); - - if (numberOfCells !== numberOfValuesToWrite) { - [writeProperty, atProperty].forEach((propertyNode) => { - validationContext.accept( - 'warning', - `The number of values to write (${numberOfValuesToWrite}) does not match the number of cells (${numberOfCells})`, - { node: propertyNode.value }, - ); - }); - } - }, - ); - this.docs.description = - 'Writes textual values into cells of a `Sheet`. The number of text values needs to match the number of cells to write into.'; - this.docs.examples = [ - { - code: blockExampleSingleCell, - description: 'Write the value "Name" into cell `A1`.', - }, - { - code: blockExampleCellRange, - description: 'Write the values "Name", "Age" into cells `A1` and `A2`.', - }, - ]; - } -} - -const blockExampleSingleCell = `block NameHeaderWriter oftype CellWriter { - at: cell A1; - write: ["Name"]; -}`; -const blockExampleCellRange = `block HeaderSequenceWriter oftype CellWriter { - at: range A1:A2; - write: ["Name", "Age"]; -}`; diff --git a/libs/extensions/tabular/lang/src/lib/column-deleter-meta-inf.spec.ts b/libs/extensions/tabular/lang/src/lib/column-deleter-meta-inf.spec.ts deleted file mode 100644 index 0875860f4..000000000 --- a/libs/extensions/tabular/lang/src/lib/column-deleter-meta-inf.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - TestLangExtension, - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { TabularLangExtension } from '../extension'; - -describe('Validation of ColumnDeleterMetaInformation', () => { - let validate: (input: string) => Promise>; - - const readJvTestAsset = readJvTestAssetHelper( - __dirname, - '../../test/assets/', - ); - - beforeAll(() => { - // Register std extension - useExtension(new TabularLangExtension()); - // Register test extension - useExtension(new TestLangExtension()); - // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it('should diagnose error on deleting partial column', async () => { - const text = readJvTestAsset( - 'column-deleter-meta-inf/invalid-partial-column-delete.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(1); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: 'An entire column needs to be selected', - }), - ]), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'column-deleter-meta-inf/valid-column-delete.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - }); -}); diff --git a/libs/extensions/tabular/lang/src/lib/column-deleter-meta-inf.ts b/libs/extensions/tabular/lang/src/lib/column-deleter-meta-inf.ts deleted file mode 100644 index 45b90d152..000000000 --- a/libs/extensions/tabular/lang/src/lib/column-deleter-meta-inf.ts +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - CollectionValuetype, - IOType, - PrimitiveValuetypes, - evaluatePropertyValue, - isColumnWrapper, -} from '@jvalue/jayvee-language-server'; - -export class ColumnDeleterMetaInformation extends BlockMetaInformation { - constructor() { - super( - 'ColumnDeleter', - { - delete: { - type: new CollectionValuetype(PrimitiveValuetypes.CellRange), - validation: (property, validationContext, evaluationContext) => { - const cellRanges = evaluatePropertyValue( - property, - evaluationContext, - new CollectionValuetype(PrimitiveValuetypes.CellRange), - ); - - cellRanges?.forEach((cellRange) => { - if (!isColumnWrapper(cellRange)) { - validationContext.accept( - 'error', - 'An entire column needs to be selected', - { - node: cellRange.astNode, - }, - ); - } - }); - }, - docs: { - description: 'The columns to delete.', - examples: [ - { - code: 'delete: [column B]', - description: 'Delete column B.', - }, - { - code: 'delete: [column B, column C]', - description: 'Delete column B and column C.', - }, - ], - validation: 'You need to specify at least one column.', - }, - }, - }, - IOType.SHEET, - IOType.SHEET, - ); - this.docs.description = - 'Deletes columns from a `Sheet`. Column IDs of subsequent columns will be shifted accordingly, so there will be no gaps.'; - this.docs.examples = [ - { - code: blockExample, - description: 'Deletes column B (i.e. the second column).', - }, - ]; - } -} - -const blockExample = `block MpgColumnDeleter oftype ColumnDeleter { - delete: [column B]; -}`; diff --git a/libs/extensions/tabular/lang/src/lib/csv-interpreter-meta-inf.ts b/libs/extensions/tabular/lang/src/lib/csv-interpreter-meta-inf.ts deleted file mode 100644 index 34b900c1b..000000000 --- a/libs/extensions/tabular/lang/src/lib/csv-interpreter-meta-inf.ts +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - IOType, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; - -export class CSVInterpreterMetaInformation extends BlockMetaInformation { - constructor() { - super( - // How the block type should be called: - 'CSVInterpreter', - // Property definitions: - { - delimiter: { - type: PrimitiveValuetypes.Text, - defaultValue: ',', - docs: { - description: 'The delimiter for values in the CSV file.', - examples: [ - { - code: 'delimiter: ","', - description: - 'Commas are used to separate values in the CSV file.', - }, - ], - }, - }, - enclosing: { - type: PrimitiveValuetypes.Text, - defaultValue: '', - docs: { - description: - 'The enclosing character that may be used for values in the CSV file.', - }, - }, - enclosingEscape: { - type: PrimitiveValuetypes.Text, - defaultValue: '', - docs: { - description: - 'The character to escape enclosing characters in values.', - }, - }, - }, - // Input type: - IOType.TEXT_FILE, - - // Output type: - IOType.SHEET, - ); - - this.docs.description = - 'Interprets an input file as a csv-file containing string-values delimited by `delimiter` and outputs a `Sheet`.'; - this.docs.examples = [ - { - code: blockExample, - description: - 'Interprets an input file as a csv-file containing string-values delimited by `;` and outputs `Sheet`.', - }, - ]; - } -} -const blockExample = `block AgencyCSVInterpreter oftype CSVInterpreter { - delimiter: ";"; - }`; diff --git a/libs/extensions/tabular/lang/src/lib/row-deleter-meta-inf.spec.ts b/libs/extensions/tabular/lang/src/lib/row-deleter-meta-inf.spec.ts deleted file mode 100644 index 4ec568451..000000000 --- a/libs/extensions/tabular/lang/src/lib/row-deleter-meta-inf.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - TestLangExtension, - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { TabularLangExtension } from '../extension'; - -describe('Validation of RowDeleterMetaInformation', () => { - let validate: (input: string) => Promise>; - - const readJvTestAsset = readJvTestAssetHelper( - __dirname, - '../../test/assets/', - ); - - beforeAll(() => { - // Register std extension - useExtension(new TabularLangExtension()); - // Register test extension - useExtension(new TestLangExtension()); - // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it('should diagnose error on deleting partial row', async () => { - const text = readJvTestAsset( - 'row-deleter-meta-inf/invalid-partial-row-delete.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(1); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: 'An entire row needs to be selected', - }), - ]), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset('row-deleter-meta-inf/valid-row-delete.jv'); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - }); -}); diff --git a/libs/extensions/tabular/lang/src/lib/row-deleter-meta-inf.ts b/libs/extensions/tabular/lang/src/lib/row-deleter-meta-inf.ts deleted file mode 100644 index 43aae44c1..000000000 --- a/libs/extensions/tabular/lang/src/lib/row-deleter-meta-inf.ts +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - CollectionValuetype, - IOType, - PrimitiveValuetypes, - evaluatePropertyValue, - isRowWrapper, -} from '@jvalue/jayvee-language-server'; - -export class RowDeleterMetaInformation extends BlockMetaInformation { - constructor() { - super( - 'RowDeleter', - { - delete: { - type: new CollectionValuetype(PrimitiveValuetypes.CellRange), - validation: (property, validationContext, evaluationContext) => { - const cellRanges = evaluatePropertyValue( - property, - evaluationContext, - new CollectionValuetype(PrimitiveValuetypes.CellRange), - ); - - cellRanges?.forEach((cellRange) => { - if (!isRowWrapper(cellRange)) { - validationContext.accept( - 'error', - 'An entire row needs to be selected', - { - node: cellRange.astNode, - }, - ); - } - }); - }, - docs: { - description: 'The rows to delete.', - examples: [ - { - code: 'delete: [row 2]', - description: 'Delete row 2.', - }, - { - code: 'delete: [row 2, row 3]', - description: 'Delete row 2 and row 3.', - }, - ], - validation: 'You need to specify at least one row.', - }, - }, - }, - IOType.SHEET, - IOType.SHEET, - ); - - this.docs.description = - 'Deletes one or more rows from a `Sheet`. Row IDs of subsequent rows will be shifted accordingly, so there will be no gaps.'; - this.docs.examples = [ - { - code: blockExample, - description: 'Deletes row 2 (i.e. the second row).', - }, - ]; - } -} - -const blockExample = `block SecondRowDeleter oftype RowDeleter { - delete: [row 2]; -}`; diff --git a/libs/extensions/tabular/lang/src/lib/sheet-picker-meta-inf.spec.ts b/libs/extensions/tabular/lang/src/lib/sheet-picker-meta-inf.spec.ts deleted file mode 100644 index 5ef6bb7ff..000000000 --- a/libs/extensions/tabular/lang/src/lib/sheet-picker-meta-inf.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - TestLangExtension, - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { TabularLangExtension } from '../extension'; - -describe('Validation of SheetPickerMetaInformation', () => { - let validate: (input: string) => Promise>; - - const readJvTestAsset = readJvTestAssetHelper( - __dirname, - '../../test/assets/', - ); - - beforeAll(() => { - // Register std extension - useExtension(new TabularLangExtension()); - // Register test extension - useExtension(new TestLangExtension()); - // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it('should diagnose error on missing parameters', async () => { - const text = readJvTestAsset( - 'sheet-picker-meta-inf/invalid-sheet-picker-missing-parameter.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(1); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: 'The following required properties are missing: "sheetName"', - }), - ]), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'sheet-picker-meta-inf/valid-correct-sheet-picker.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - }); -}); diff --git a/libs/extensions/tabular/lang/src/lib/sheet-picker-meta-inf.ts b/libs/extensions/tabular/lang/src/lib/sheet-picker-meta-inf.ts deleted file mode 100644 index 518560040..000000000 --- a/libs/extensions/tabular/lang/src/lib/sheet-picker-meta-inf.ts +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - IOType, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; - -export class SheetPickerMetaInformation extends BlockMetaInformation { - constructor() { - super( - // How the block type should be called: - 'SheetPicker', - // Property definitions: - { - sheetName: { - type: PrimitiveValuetypes.Text, - docs: { - description: 'The name of the sheet to select.', - }, - }, - }, - // Input type: - IOType.WORKBOOK, - - // Output type: - IOType.SHEET, - ); - - this.docs.description = - 'Selects one `Sheet` from a `Workbook` based on its `sheetName`. If no sheet matches the name, no output is created and the execution of the pipeline is aborted.'; - this.docs.examples = [ - { - code: `block AgencySheetPicker oftype SheetPicker { - sheetName: "AgencyNames"; -}`, - description: - 'Tries to pick the sheet `AgencyNames` from the provided `Workbook`. If `AgencyNames` exists it is passed on as `Sheet`, if it does not exist the execution of the pipeline is aborted.', - }, - ]; - } -} diff --git a/libs/extensions/tabular/lang/src/lib/table-interpreter-meta-inf.spec.ts b/libs/extensions/tabular/lang/src/lib/table-interpreter-meta-inf.spec.ts deleted file mode 100644 index 0ad7f640c..000000000 --- a/libs/extensions/tabular/lang/src/lib/table-interpreter-meta-inf.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - TestLangExtension, - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { TabularLangExtension } from '../extension'; - -describe('Validation of TableInterpreterMetaInformation', () => { - let validate: (input: string) => Promise>; - - const readJvTestAsset = readJvTestAssetHelper( - __dirname, - '../../test/assets/', - ); - - beforeAll(() => { - // Register std extension - useExtension(new TabularLangExtension()); - // Register test extension - useExtension(new TestLangExtension()); - // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it('should diagnose error on non unique column names', async () => { - const text = readJvTestAsset( - 'table-interpreter-meta-inf/invalid-non-unique-column-names.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(2); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: 'The column name "name" needs to be unique.', - }), - expect.objectContaining({ - message: 'The column name "name" needs to be unique.', - }), - ]), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'table-interpreter-meta-inf/valid-correct-table.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - }); -}); diff --git a/libs/extensions/tabular/lang/src/lib/table-interpreter-meta-inf.ts b/libs/extensions/tabular/lang/src/lib/table-interpreter-meta-inf.ts deleted file mode 100644 index 15c514131..000000000 --- a/libs/extensions/tabular/lang/src/lib/table-interpreter-meta-inf.ts +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - CollectionValuetype, - IOType, - PrimitiveValuetypes, - checkUniqueNames, - evaluatePropertyValue, -} from '@jvalue/jayvee-language-server'; - -export class TableInterpreterMetaInformation extends BlockMetaInformation { - constructor() { - super( - 'TableInterpreter', - { - header: { - type: PrimitiveValuetypes.Boolean, - docs: { - description: - 'Whether the first row should be interpreted as header row.', - examples: [ - { - code: 'header: true', - description: - 'The first row is interpreted as table header. The values in the header row will become the column names of the table.', - }, - { - code: 'header: false', - description: - 'The first row is NOT interpreted as table header and columns of the sheet are directly mapped to table columns. The column names are taken form the provided names in the `columns` property.', - }, - ], - }, - }, - columns: { - type: new CollectionValuetype( - PrimitiveValuetypes.ValuetypeAssignment, - ), - validation: (property, validationContext, evaluationContext) => { - const valuetypeAssignments = evaluatePropertyValue( - property, - evaluationContext, - new CollectionValuetype(PrimitiveValuetypes.ValuetypeAssignment), - ); - if (valuetypeAssignments === undefined) { - return; - } - - checkUniqueNames(valuetypeAssignments, validationContext, 'column'); - }, - docs: { - description: - 'Collection of valuetype assignments. Uses column names (potentially matched with the header or by sequence depending on the `header` property) to assign a primitive valuetype to each column.', - examples: [ - { - code: 'columns: [ "name" oftype text ]', - description: - 'There is one column with the header "name". All values in this colum are typed as text.', - }, - ], - validation: - 'Needs to be a collection of valuetype assignments. Each column needs to have a unique name.', - }, - }, - }, - IOType.SHEET, - IOType.TABLE, - ); - this.docs.description = - 'Interprets a `Sheet` as a `Table`. In case a header row is present in the sheet, its names can be matched with the provided column names. Otherwise, the provided column names are assigned in order.'; - this.docs.examples = [ - { - code: blockExampleWithHeader, - description: - 'Interprets a `Sheet` about cars with a topmost header row and interprets it as a `Table` by assigning a primitive valuetype to each column. The column names are matched to the header, so the order of the type assignments does not matter.', - }, - { - code: blockExampleWithoutHeader, - description: - 'Interprets a `Sheet` about cars without a topmost header row and interprets it as a `Table` by sequentially assigning a name and a primitive valuetype to each column of the sheet. Note that the order of columns matters here. The first column (column `A`) will be named "name", the second column (column `B`) will be named "mpg" etc.', - }, - ]; - } -} - -const blockExampleWithHeader = `block CarsTableInterpreter oftype TableInterpreter { - header: true; - columns: [ - "name" oftype text, - "mpg" oftype decimal, - "cyl" oftype integer, - ]; -}`; - -const blockExampleWithoutHeader = `block CarsTableInterpreter oftype TableInterpreter { - header: false; - columns: [ - "name" oftype text, - "mpg" oftype decimal, - "cyl" oftype integer, - ]; -}`; diff --git a/libs/extensions/tabular/lang/src/lib/table-transformer-meta-inf.spec.ts b/libs/extensions/tabular/lang/src/lib/table-transformer-meta-inf.spec.ts deleted file mode 100644 index 6f4fff372..000000000 --- a/libs/extensions/tabular/lang/src/lib/table-transformer-meta-inf.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - TestLangExtension, - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { TabularLangExtension } from '../extension'; - -describe('Validation of TableTransformerMetaInformation', () => { - let validate: (input: string) => Promise>; - - const readJvTestAsset = readJvTestAssetHelper( - __dirname, - '../../test/assets/', - ); - - beforeAll(() => { - // Register std extension - useExtension(new TabularLangExtension()); - // Register test extension - useExtension(new TestLangExtension()); - // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it('should diagnose error on number of input columns do not match transform input ports', async () => { - const text = readJvTestAsset( - 'table-transformer-meta-inf/invalid-input-columns-transform-port-missmatch.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(1); - expect(diagnostics).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: 'Expected 1 columns but only got 2', - }), - ]), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'table-transformer-meta-inf/valid-correct-ports.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - }); -}); diff --git a/libs/extensions/tabular/lang/src/lib/table-transformer-meta-inf.ts b/libs/extensions/tabular/lang/src/lib/table-transformer-meta-inf.ts deleted file mode 100644 index 43b25a193..000000000 --- a/libs/extensions/tabular/lang/src/lib/table-transformer-meta-inf.ts +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - BlockMetaInformation, - CollectionValuetype, - EvaluationContext, - IOType, - PrimitiveValuetypes, - PropertyBody, - ValidationContext, - evaluatePropertyValue, -} from '@jvalue/jayvee-language-server'; - -export class TableTransformerMetaInformation extends BlockMetaInformation { - constructor() { - super( - 'TableTransformer', - { - inputColumns: { - type: new CollectionValuetype(PrimitiveValuetypes.Text), - docs: { - description: - "The names of the input columns. The columns have to be present in the table and match with the transform's input port types.", - }, - }, - outputColumn: { - type: PrimitiveValuetypes.Text, - docs: { - description: - 'The name of the output column. Overwrites the column if it already exists, or otherwise creates a new one.', - }, - }, - use: { - type: PrimitiveValuetypes.Transform, - docs: { - description: - 'Reference to the transform that is applied to the column.', - }, - }, - }, - IOType.TABLE, - IOType.TABLE, - (property, validationContext, evaluationContext) => { - this.checkInputColumnsMatchTransformationPorts( - property, - validationContext, - evaluationContext, - ); - }, - ); - this.docs = { - description: - 'Applies a transform on each value of a column. The input port type of the used transform has to match the type of the input column.', - examples: [ - { - description: - 'Given a column "temperature" with temperature values in Celsius, it overwrites the column with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model.', - code: blockExampleOverwrite, - }, - { - description: - 'Given a column "temperatureCelsius" with temperature values in Celsius, it adds a new column "temperatureFahrenheit" with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model.', - code: blockExampleNewCol, - }, - ], - }; - } - - private checkInputColumnsMatchTransformationPorts( - body: PropertyBody, - validationContext: ValidationContext, - evaluationContext: EvaluationContext, - ): void { - const useProperty = body.properties.find((x) => x.name === 'use'); - const inputColumnsProperty = body.properties.find( - (x) => x.name === 'inputColumns', - ); - - if (useProperty === undefined || inputColumnsProperty === undefined) { - return; - } - - const transform = evaluatePropertyValue( - useProperty, - evaluationContext, - PrimitiveValuetypes.Transform, - ); - const inputColumns = evaluatePropertyValue( - inputColumnsProperty, - evaluationContext, - new CollectionValuetype(PrimitiveValuetypes.Text), - ); - - if (transform === undefined || inputColumns === undefined) { - return; - } - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - const transformInputPorts = transform?.body?.ports?.filter( - (x) => x.kind === 'from', - ); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (transformInputPorts === undefined) { - return; - } - - const numberTransformPorts = transformInputPorts.length; - const numberInputColumns = inputColumns.length; - - if (numberTransformPorts !== numberInputColumns) { - validationContext.accept( - 'error', - `Expected ${numberTransformPorts} columns but only got ${numberInputColumns}`, - { - node: inputColumnsProperty, - }, - ); - } - } -} - -const blockExampleOverwrite = ` -transform CelsiusToFahrenheit { - from Celsius oftype decimal; - to Fahrenheit oftype decimal; - - Fahrenheit: (Celsius * 9/5) + 32; -} - -block CelsiusToFahrenheitTransformer oftype TableTransformer { - inputColumns: ['temperature']; - outputColumn: 'temperature'; - use: CelsiusToFahrenheit; -}`; - -const blockExampleNewCol = ` -transform CelsiusToFahrenheit { - from Celsius oftype decimal; - to Fahrenheit oftype decimal; - - Fahrenheit: (Celsius * 9/5) + 32; -} - -block CelsiusToFahrenheitTransformer oftype TableTransformer { - inputColumns: ['temperatureCelsius']; - outputColumn: 'temperatureFahrenheit'; - use: CelsiusToFahrenheit; -}`; diff --git a/libs/extensions/tabular/lang/src/lib/xlsx-interpreter-meta-inf.spec.ts b/libs/extensions/tabular/lang/src/lib/xlsx-interpreter-meta-inf.spec.ts deleted file mode 100644 index e4a7f9f7d..000000000 --- a/libs/extensions/tabular/lang/src/lib/xlsx-interpreter-meta-inf.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; -import { - TestLangExtension, - ValidationResult, - readJvTestAssetHelper, - validationHelper, -} from '@jvalue/jayvee-language-server/test'; -import { AstNode } from 'langium'; -import { NodeFileSystem } from 'langium/node'; - -import { TabularLangExtension } from '../extension'; - -describe('Validation of XLSXInterpreterMetaInformation', () => { - let validate: (input: string) => Promise>; - - const readJvTestAsset = readJvTestAssetHelper( - __dirname, - '../../test/assets/', - ); - - beforeAll(() => { - // Register std extension - useExtension(new TabularLangExtension()); - // Register test extension - useExtension(new TestLangExtension()); - // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; - // Create validation helper for language services - validate = validationHelper(services); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'xlsx-interpreter-meta-inf/valid-xlsx-interpreter.jv', - ); - - const validationResult = await validate(text); - const diagnostics = validationResult.diagnostics; - - expect(diagnostics).toHaveLength(0); - }); -}); diff --git a/libs/extensions/tabular/lang/src/lib/xlsx-interpreter-meta-inf.ts b/libs/extensions/tabular/lang/src/lib/xlsx-interpreter-meta-inf.ts deleted file mode 100644 index 70020414d..000000000 --- a/libs/extensions/tabular/lang/src/lib/xlsx-interpreter-meta-inf.ts +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { BlockMetaInformation, IOType } from '@jvalue/jayvee-language-server'; - -export class XLSXInterpreterMetaInformation extends BlockMetaInformation { - constructor() { - super( - // How the block type should be called: - 'XLSXInterpreter', - // Property definitions: - {}, - // Input type: - IOType.FILE, - - // Output type: - IOType.WORKBOOK, - ); - - this.docs.description = - 'Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s.'; - this.docs.examples = [ - { - code: blockExample, - description: - 'Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s.', - }, - ]; - } -} -const blockExample = `block AgencyXLSXInterpreter oftype XLSXInterpreter { - }`; diff --git a/libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/invalid-write-length-does-not-match-cell-range.jv b/libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/invalid-write-length-does-not-match-cell-range.jv deleted file mode 100644 index 9384c99aa..000000000 --- a/libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/invalid-write-length-does-not-match-cell-range.jv +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype CellWriter { - at: range A1:A4; - write: ['values', 'to', 'write']; - } - - block TestExtractor oftype TestSheetExtractor { - } - - block TestLoader oftype TestSheetLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/invalid-wrong-at-dimension.jv b/libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/invalid-wrong-at-dimension.jv deleted file mode 100644 index d8154bf76..000000000 --- a/libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/invalid-wrong-at-dimension.jv +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype CellWriter { - at: range A1:B2; - write: ['the', 'values', 'to', 'write']; - } - - block TestExtractor oftype TestSheetExtractor { - } - - block TestLoader oftype TestSheetLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/valid-range-matches-array-length.jv b/libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/valid-range-matches-array-length.jv deleted file mode 100644 index 2d9a51d5f..000000000 --- a/libs/extensions/tabular/lang/test/assets/cell-writer-meta-inf/valid-range-matches-array-length.jv +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype CellWriter { - at: range A1:A3; - write: ['values', 'to', 'write']; - } - - block TestExtractor oftype TestSheetExtractor { - } - - block TestLoader oftype TestSheetLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/column-deleter-meta-inf/invalid-partial-column-delete.jv b/libs/extensions/tabular/lang/test/assets/column-deleter-meta-inf/invalid-partial-column-delete.jv deleted file mode 100644 index 981dab3ae..000000000 --- a/libs/extensions/tabular/lang/test/assets/column-deleter-meta-inf/invalid-partial-column-delete.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype ColumnDeleter { - delete: [range A1:A3]; - } - - block TestExtractor oftype TestSheetExtractor { - } - - block TestLoader oftype TestSheetLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/column-deleter-meta-inf/valid-column-delete.jv b/libs/extensions/tabular/lang/test/assets/column-deleter-meta-inf/valid-column-delete.jv deleted file mode 100644 index 29da54be1..000000000 --- a/libs/extensions/tabular/lang/test/assets/column-deleter-meta-inf/valid-column-delete.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype ColumnDeleter { - delete: [column A]; - } - - block TestExtractor oftype TestSheetExtractor { - } - - block TestLoader oftype TestSheetLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/row-deleter-meta-inf/invalid-partial-row-delete.jv b/libs/extensions/tabular/lang/test/assets/row-deleter-meta-inf/invalid-partial-row-delete.jv deleted file mode 100644 index 80c2e8e34..000000000 --- a/libs/extensions/tabular/lang/test/assets/row-deleter-meta-inf/invalid-partial-row-delete.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype RowDeleter { - delete: [range A1:C1]; - } - - block TestExtractor oftype TestSheetExtractor { - } - - block TestLoader oftype TestSheetLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/row-deleter-meta-inf/valid-row-delete.jv b/libs/extensions/tabular/lang/test/assets/row-deleter-meta-inf/valid-row-delete.jv deleted file mode 100644 index 673fe5f6d..000000000 --- a/libs/extensions/tabular/lang/test/assets/row-deleter-meta-inf/valid-row-delete.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype RowDeleter { - delete: [row 1]; - } - - block TestExtractor oftype TestSheetExtractor { - } - - block TestLoader oftype TestSheetLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/sheet-picker-meta-inf/invalid-sheet-picker-missing-parameter.jv b/libs/extensions/tabular/lang/test/assets/sheet-picker-meta-inf/invalid-sheet-picker-missing-parameter.jv deleted file mode 100644 index add4f8876..000000000 --- a/libs/extensions/tabular/lang/test/assets/sheet-picker-meta-inf/invalid-sheet-picker-missing-parameter.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block TestSheetPicker oftype SheetPicker { - } - - - block TestExtractor oftype TestWorkbookExtractor { - } - - block TestLoader oftype TestSheetLoader { - } - - TestExtractor -> TestSheetPicker -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/sheet-picker-meta-inf/valid-correct-sheet-picker.jv b/libs/extensions/tabular/lang/test/assets/sheet-picker-meta-inf/valid-correct-sheet-picker.jv deleted file mode 100644 index 901d531e3..000000000 --- a/libs/extensions/tabular/lang/test/assets/sheet-picker-meta-inf/valid-correct-sheet-picker.jv +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block TestSheetPicker oftype SheetPicker { - sheetName: "TestName"; - } - - - block TestExtractor oftype TestWorkbookExtractor { - } - - block TestLoader oftype TestSheetLoader { - } - - TestExtractor -> TestSheetPicker -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/table-interpreter-meta-inf/invalid-non-unique-column-names.jv b/libs/extensions/tabular/lang/test/assets/table-interpreter-meta-inf/invalid-non-unique-column-names.jv deleted file mode 100644 index 197e2d49a..000000000 --- a/libs/extensions/tabular/lang/test/assets/table-interpreter-meta-inf/invalid-non-unique-column-names.jv +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype TableInterpreter { - header: false; - columns: [ - "name" oftype text, - "name" oftype integer, - ]; - } - - block TestExtractor oftype TestSheetExtractor { - } - - block TestLoader oftype TestTableLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/table-interpreter-meta-inf/valid-correct-table.jv b/libs/extensions/tabular/lang/test/assets/table-interpreter-meta-inf/valid-correct-table.jv deleted file mode 100644 index 22bbbae40..000000000 --- a/libs/extensions/tabular/lang/test/assets/table-interpreter-meta-inf/valid-correct-table.jv +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype TableInterpreter { - header: false; - columns: [ - "name" oftype text, - "version" oftype integer, - ]; - } - - block TestExtractor oftype TestSheetExtractor { - } - - block TestLoader oftype TestTableLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/table-transformer-meta-inf/invalid-input-columns-transform-port-missmatch.jv b/libs/extensions/tabular/lang/test/assets/table-transformer-meta-inf/invalid-input-columns-transform-port-missmatch.jv deleted file mode 100644 index 4179d0a04..000000000 --- a/libs/extensions/tabular/lang/test/assets/table-transformer-meta-inf/invalid-input-columns-transform-port-missmatch.jv +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - transform TestTransform { - from inputParam oftype decimal; - to result oftype integer; - - result: ceil(inputParam); - } - - block Test oftype TableTransformer { - inputColumns: ['input1', 'input2']; - outputColumn: 'output'; - use: TestTransform; - } - - block TestExtractor oftype TestTableExtractor { - } - - block TestLoader oftype TestTableLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/table-transformer-meta-inf/valid-correct-ports.jv b/libs/extensions/tabular/lang/test/assets/table-transformer-meta-inf/valid-correct-ports.jv deleted file mode 100644 index c6da883da..000000000 --- a/libs/extensions/tabular/lang/test/assets/table-transformer-meta-inf/valid-correct-ports.jv +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - transform TestTransform { - from inputParam oftype decimal; - to result oftype integer; - - result: ceil(inputParam); - } - - block Test oftype TableTransformer { - inputColumns: ['input1']; - outputColumn: 'output'; - use: TestTransform; - } - - block TestExtractor oftype TestTableExtractor { - } - - block TestLoader oftype TestTableLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/test/assets/xlsx-interpreter-meta-inf/valid-xlsx-interpreter.jv b/libs/extensions/tabular/lang/test/assets/xlsx-interpreter-meta-inf/valid-xlsx-interpreter.jv deleted file mode 100644 index 3e540c38c..000000000 --- a/libs/extensions/tabular/lang/test/assets/xlsx-interpreter-meta-inf/valid-xlsx-interpreter.jv +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -pipeline Pipeline { - block Test oftype XLSXInterpreter { - } - - - block TestExtractor oftype TestFileExtractor { - } - - block TestLoader oftype TestWorkbookLoader { - } - - TestExtractor -> Test -> TestLoader; -} diff --git a/libs/extensions/tabular/lang/tsconfig.json b/libs/extensions/tabular/lang/tsconfig.json deleted file mode 100644 index 4022fd4d0..000000000 --- a/libs/extensions/tabular/lang/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../../../../tsconfig.base.json", - "compilerOptions": { - "module": "commonjs", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" - } - ] -} diff --git a/libs/extensions/tabular/lang/tsconfig.json.license b/libs/extensions/tabular/lang/tsconfig.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/tabular/lang/tsconfig.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/tabular/lang/tsconfig.lib.json b/libs/extensions/tabular/lang/tsconfig.lib.json deleted file mode 100644 index 18f2d37a1..000000000 --- a/libs/extensions/tabular/lang/tsconfig.lib.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../../dist/out-tsc", - "declaration": true, - "types": ["node"] - }, - "include": ["src/**/*.ts"], - "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] -} diff --git a/libs/extensions/tabular/lang/tsconfig.lib.json.license b/libs/extensions/tabular/lang/tsconfig.lib.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/tabular/lang/tsconfig.lib.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/extensions/tabular/lang/tsconfig.spec.json b/libs/extensions/tabular/lang/tsconfig.spec.json deleted file mode 100644 index 6668655fc..000000000 --- a/libs/extensions/tabular/lang/tsconfig.spec.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "include": [ - "jest.config.ts", - "src/**/*.test.ts", - "src/**/*.spec.ts", - "src/**/*.d.ts" - ] -} diff --git a/libs/extensions/tabular/lang/tsconfig.spec.json.license b/libs/extensions/tabular/lang/tsconfig.spec.json.license deleted file mode 100644 index 17c5d2bad..000000000 --- a/libs/extensions/tabular/lang/tsconfig.spec.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg - -SPDX-License-Identifier: AGPL-3.0-only diff --git a/libs/interpreter-lib/src/interpreter.ts b/libs/interpreter-lib/src/interpreter.ts index 75f586c5c..ecb5d22ac 100644 --- a/libs/interpreter-lib/src/interpreter.ts +++ b/libs/interpreter-lib/src/interpreter.ts @@ -17,7 +17,6 @@ import { } from '@jvalue/jayvee-execution'; import * as R from '@jvalue/jayvee-execution'; import { StdExecExtension } from '@jvalue/jayvee-extensions/std/exec'; -import { StdLangExtension } from '@jvalue/jayvee-extensions/std/lang'; import { BlockDefinition, EvaluationContext, @@ -29,7 +28,6 @@ import { collectStartingBlocks, createJayveeServices, getBlocksInTopologicalSorting, - useExtension as useLangExtension, } from '@jvalue/jayvee-language-server'; import * as chalk from 'chalk'; import { NodeFileSystem } from 'langium/node'; @@ -136,7 +134,6 @@ function setupRuntimeParameterProvider( } export function useStdExtension() { - useLangExtension(new StdLangExtension()); useExecutionExtension(new StdExecExtension()); } diff --git a/libs/interpreter-lib/src/parsing-util.ts b/libs/interpreter-lib/src/parsing-util.ts index a08029a09..1268e3d1d 100644 --- a/libs/interpreter-lib/src/parsing-util.ts +++ b/libs/interpreter-lib/src/parsing-util.ts @@ -79,6 +79,7 @@ export async function validateDocument( for (const errDiagnostic of errDiagnostics) { logger.logLanguageServerDiagnostic(errDiagnostic, document); } + throw new Error(errDiagnostics.map((r) => r.message).join('\n')); process.exit(ExitCode.FAILURE); } diff --git a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts index a6851c17a..1d3be1893 100644 --- a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts +++ b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts @@ -36,7 +36,6 @@ import { BlockMetaInformation } from '../meta-information'; import { MetaInformation } from '../meta-information/meta-inf'; import { getConstraintMetaInf, - getRegisteredBlockMetaInformation, getRegisteredConstraintMetaInformation, } from '../meta-information/meta-inf-registry'; @@ -88,22 +87,33 @@ export class JayveeCompletionProvider extends DefaultCompletionProvider { private completionForBlockType( acceptor: CompletionAcceptor, ): MaybePromise { - getRegisteredBlockMetaInformation().forEach((metaInf) => { - const lspDocBuilder = new LspDocGenerator(); - const markdownDoc = lspDocBuilder.generateBlockTypeDoc(metaInf); - acceptor({ - label: metaInf.type, - labelDetails: { - detail: ` ${metaInf.inputType} ${RIGHT_ARROW_SYMBOL} ${metaInf.outputType}`, - }, - kind: CompletionItemKind.Class, - detail: `(block type)`, - documentation: { - kind: 'markdown', - value: markdownDoc, - }, + this.langiumDocumentService.all + .map((document) => document.parseResult.value) + .forEach((parsedDocument) => { + if (!isJayveeModel(parsedDocument)) { + throw new Error('Expected parsed document to be a JayveeModel'); + } + parsedDocument.blocktypes.forEach((blocktypeDefinition) => { + if (!BlockMetaInformation.canBeWrapped(blocktypeDefinition)) { + return; + } + const blocktype = new BlockMetaInformation(blocktypeDefinition); + const lspDocBuilder = new LspDocGenerator(); + const markdownDoc = lspDocBuilder.generateBlockTypeDoc(blocktype); + acceptor({ + label: blocktype.type, + labelDetails: { + detail: ` ${blocktype.inputType} ${RIGHT_ARROW_SYMBOL} ${blocktype.outputType}`, + }, + kind: CompletionItemKind.Class, + detail: `(block type)`, + documentation: { + kind: 'markdown', + value: markdownDoc, + }, + }); + }); }); - }); } private completionForConstraintType( diff --git a/libs/language-server/src/lib/extension.ts b/libs/language-server/src/lib/extension.ts deleted file mode 100644 index e4a7d0799..000000000 --- a/libs/language-server/src/lib/extension.ts +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { BlockMetaInformation } from './meta-information'; -import { registerBlockMetaInf } from './meta-information/meta-inf-registry'; -import { ConstructorClass } from './util/constructor-class'; - -export interface JayveeLangExtension { - getBlockMetaInf(): Array>; -} - -export function useExtension(extension: JayveeLangExtension) { - extension.getBlockMetaInf().forEach(registerBlockMetaInf); -} diff --git a/libs/language-server/src/lib/meta-information/block-meta-inf.ts b/libs/language-server/src/lib/meta-information/block-meta-inf.ts index 4c8f046b6..ce5730122 100644 --- a/libs/language-server/src/lib/meta-information/block-meta-inf.ts +++ b/libs/language-server/src/lib/meta-information/block-meta-inf.ts @@ -7,11 +7,18 @@ import { strict as assert } from 'assert'; import { Reference, isReference } from 'langium'; // eslint-disable-next-line import/no-cycle -import { IOType, createValuetype, getIOType } from '../ast'; +import { + EvaluationContext, + IOType, + createValuetype, + evaluateExpression, + getIOType, +} from '../ast'; import { ReferenceableBlocktypeDefinition, isBuiltinBlocktypeDefinition, } from '../ast/generated/ast'; +import { RuntimeParameterProvider } from '../services'; import { ExampleDoc, MetaInformation, PropertySpecification } from './meta-inf'; @@ -46,6 +53,15 @@ export class BlockMetaInformation extends MetaInformation { properties[property.name] = { type: valuetype, }; + + const defaultValue = evaluateExpression( + property.defaultValue, + new EvaluationContext(new RuntimeParameterProvider()), // TODO: check if that works + ); + if (defaultValue !== undefined) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + properties[property.name]!.defaultValue = defaultValue; + } } super(blocktypeName, properties, undefined); diff --git a/libs/language-server/src/lib/meta-information/meta-inf-registry.ts b/libs/language-server/src/lib/meta-information/meta-inf-registry.ts index 262d62a0d..d1a536de3 100644 --- a/libs/language-server/src/lib/meta-information/meta-inf-registry.ts +++ b/libs/language-server/src/lib/meta-information/meta-inf-registry.ts @@ -6,30 +6,16 @@ import { strict as assert } from 'assert'; import { Reference, isReference } from 'langium'; -import { - BuiltinConstrainttypeDefinition, - ReferenceableBlocktypeDefinition, - isCompositeBlocktypeDefinition, -} from '../ast/generated/ast'; +import { BuiltinConstrainttypeDefinition } from '../ast/generated/ast'; import { ConstructorClass } from '../util/constructor-class'; import { Registry } from '../util/registry'; // eslint-disable-next-line import/no-cycle -import { BlockMetaInformation } from './block-meta-inf'; -import { CompositeBlocktypeMetaInformation } from './composite-blocktype-meta-inf'; import { ConstraintMetaInformation } from './constraint-meta-inf'; -export const blockMetaInfRegistry = new Registry(); export const constraintMetaInfRegistry = new Registry(); -export function registerBlockMetaInf( - metaInfClass: ConstructorClass, -) { - const metaInf = new metaInfClass(); - blockMetaInfRegistry.register(metaInf.type, metaInf); -} - export function registerConstraintMetaInf( metaInfClass: ConstructorClass, ) { @@ -37,36 +23,6 @@ export function registerConstraintMetaInf( constraintMetaInfRegistry.register(metaInf.type, metaInf); } -export function getBlockMetaInf( - type: - | ReferenceableBlocktypeDefinition - | Reference - | undefined, -): BlockMetaInformation | undefined { - const dereferencedType = isReference(type) ? type.ref : type; - if (dereferencedType === undefined) { - return undefined; - } - - // Register meta information about composite blocks from jv code - if ( - isCompositeBlocktypeDefinition(dereferencedType) && - !blockMetaInfRegistry.get(dereferencedType.name) - ) { - blockMetaInfRegistry.register( - dereferencedType.name, - new CompositeBlocktypeMetaInformation(dereferencedType), - ); - } - - const metaInf = blockMetaInfRegistry.get(dereferencedType.name); - if (metaInf === undefined) { - return undefined; - } - - return metaInf; -} - export function getConstraintMetaInf( type: | BuiltinConstrainttypeDefinition @@ -86,29 +42,10 @@ export function getConstraintMetaInf( return metaInf; } -export function getRegisteredBlockMetaInformation(): BlockMetaInformation[] { - return blockMetaInfRegistry.getAll(); -} - export function getRegisteredConstraintMetaInformation(): ConstraintMetaInformation[] { return constraintMetaInfRegistry.getAll(); } -export function getOrFailBockMetaInf( - type: - | ReferenceableBlocktypeDefinition - | Reference, -): BlockMetaInformation { - const result = getBlockMetaInf(type); - const typeName = - (isReference(type) ? type.ref?.name : type.name) ?? ''; - assert( - result !== undefined, - `Meta information for blocktype ${typeName} was expected to be present, got undefined instead`, - ); - return result; -} - export function getOrFailConstraintMetaInf( type: | BuiltinConstrainttypeDefinition diff --git a/libs/language-server/src/stdlib/blocktypes.jv b/libs/language-server/src/stdlib/blocktypes.jv deleted file mode 100644 index 977a2111b..000000000 --- a/libs/language-server/src/stdlib/blocktypes.jv +++ /dev/null @@ -1,406 +0,0 @@ -/* -Deletes columns from a `Sheet`. Column IDs of subsequent columns will be shifted accordingly, so there will be no gaps. - -@example Deletes column B (i.e. the second column). -block MpgColumnDeleter oftype ColumnDeleter { - delete: [column B]; -} -*/ -builtin blocktype ColumnDeleter { - input default oftype Sheet; - output default oftype Sheet; - - // The columns to delete. - property delete oftype Collection; -} - -/* -Deletes one or more rows from a `Sheet`. Row IDs of subsequent rows will be shifted accordingly, so there will be no gaps. - -@example Deletes row 2 (i.e. the second row). -block SecondRowDeleter oftype RowDeleter { - delete: [row 2]; -} -*/ -builtin blocktype RowDeleter { - input default oftype Sheet; - output default oftype Sheet; - - // The rows to delete. - property delete oftype Collection; -} - -/* -Selects a subset of a `Sheet` to produce a new `Sheet`. - -@example Selects the cells in the given range and produces a new `Sheet` containing only the selected cells. -block CarsCoreDataSelector oftype CellRangeSelector { - select: range A1:E*; -} -*/ -builtin blocktype CellRangeSelector { - input default oftype Sheet; - output default oftype Sheet; - - // The cell range to select. - property select oftype CellRange; -} - -/* -Writes textual values into cells of a `Sheet`. The number of text values needs to match the number of cells to write into. - -@example Write the value "Name" into cell `A1`. -block NameHeaderWriter oftype CellWriter { - at: cell A1; - write: ["Name"]; -} - -@example Write the values "Name", "Age" into cells `A1` and `A2`. -block HeaderSequenceWriter oftype CellWriter { - at: range A1:A2; - write: ["Name", "Age"]; -} -*/ -builtin blocktype CellWriter { - input default oftype Sheet; - output default oftype Sheet; - - // The values to write. - property write oftype Collection; - // The cells to write into. - property at oftype CellRange; -} - -/* -Interprets a `Sheet` as a `Table`. In case a header row is present in the sheet, its names can be matched with the provided column names. Otherwise, the provided column names are assigned in order. - -@example Interprets a `Sheet` about cars with a topmost header row and interprets it as a `Table` by assigning a primitive valuetype to each column. The column names are matched to the header, so the order of the type assignments does not matter. -block CarsTableInterpreter oftype TableInterpreter { - header: true; - columns: [ - "name" oftype text, - "mpg" oftype decimal, - "cyl" oftype integer, - ]; -} - -@example Interprets a `Sheet` about cars without a topmost header row and interprets it as a `Table` by sequentially assigning a name and a primitive valuetype to each column of the sheet. Note that the order of columns matters here. The first column (column `A`) will be named "name", the second column (column `B`) will be named "mpg" etc. -block CarsTableInterpreter oftype TableInterpreter { - header: false; - columns: [ - "name" oftype text, - "mpg" oftype decimal, - "cyl" oftype integer, - ]; -} -*/ -builtin blocktype TableInterpreter { - input default oftype Sheet; - output default oftype Table; - - // Whether the first row should be interpreted as header row. - property header oftype boolean; - // Collection of valuetype assignments. Uses column names (potentially matched with the header or by sequence depending on the `header` property) to assign a primitive valuetype to each column. - property columns oftype Collection; -} - -/* -Interprets an input file as a csv-file containing string-values delimited by `delimiter` and outputs a `Sheet`. - -@example Interprets an input file as a csv-file containing string-values delimited by `;` and outputs `Sheet`. -block AgencyCSVInterpreter oftype CSVInterpreter { - delimiter: ";"; - } -*/ -builtin blocktype CSVInterpreter { - input default oftype TextFile; - output default oftype Sheet; - - // The delimiter for values in the CSV file. - property delimiter oftype text; - // The enclosing character that may be used for values in the CSV file. - property enclosing oftype text; - // The character to escape enclosing characters in values. - property enclosingEscape oftype text; -} - -/* -Applies a transform on each value of a column. The input port type of the used transform has to match the type of the input column. - -@example Given a column "temperature" with temperature values in Celsius, it overwrites the column with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model. - -transform CelsiusToFahrenheit { - from Celsius oftype decimal; - to Fahrenheit oftype decimal; - - Fahrenheit: (Celsius * 9/5) + 32; -} - -block CelsiusToFahrenheitTransformer oftype TableTransformer { - inputColumns: ['temperature']; - outputColumn: 'temperature'; - use: CelsiusToFahrenheit; -} - -@example Given a column "temperatureCelsius" with temperature values in Celsius, it adds a new column "temperatureFahrenheit" with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model. - -transform CelsiusToFahrenheit { - from Celsius oftype decimal; - to Fahrenheit oftype decimal; - - Fahrenheit: (Celsius * 9/5) + 32; -} - -block CelsiusToFahrenheitTransformer oftype TableTransformer { - inputColumns: ['temperatureCelsius']; - outputColumn: 'temperatureFahrenheit'; - use: CelsiusToFahrenheit; -} -*/ -builtin blocktype TableTransformer { - input default oftype Table; - output default oftype Table; - - // The names of the input columns. The columns have to be present in the table and match with the transform's input port types. - property inputColumns oftype Collection; - // The name of the output column. Overwrites the column if it already exists, or otherwise creates a new one. - property outputColumn oftype text; - // Reference to the transform that is applied to the column. - property use oftype Transform; -} - -/* -Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s. - -@example Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s. -block AgencyXLSXInterpreter oftype XLSXInterpreter { - } -*/ -builtin blocktype XLSXInterpreter { - input default oftype File; - output default oftype Workbook; - -} - -/* -Selects one `Sheet` from a `Workbook` based on its `sheetName`. If no sheet matches the name, no output is created and the execution of the pipeline is aborted. - -@example Tries to pick the sheet `AgencyNames` from the provided `Workbook`. If `AgencyNames` exists it is passed on as `Sheet`, if it does not exist the execution of the pipeline is aborted. -block AgencySheetPicker oftype SheetPicker { - sheetName: "AgencyNames"; -} -*/ -builtin blocktype SheetPicker { - input default oftype Workbook; - output default oftype Sheet; - - // The name of the sheet to select. - property sheetName oftype text; -} - -/* -Loads a `Table` into a PostgreSQL database sink. - -@example A local Postgres instance is filled with table data about cars. -block CarsLoader oftype PostgresLoader { - host: "localhost"; - port: 5432; - username: "postgres"; - password: "postgres"; - database: "CarsDB"; - table: "Cars"; -} -*/ -builtin blocktype PostgresLoader { - input default oftype Table; - output default oftype None; - - // The hostname or IP address of the Postgres database. - property host oftype text; - // The port of the Postgres database. - property port oftype integer; - // The username to login to the Postgres database. - property username oftype text; - // The password to login to the Postgres database. - property password oftype text; - // The database to use. - property database oftype text; - // The name of the table to write into. - property table oftype text; -} - -/* -Loads a `Table` into a SQLite database sink. - -@example A SQLite file `cars.db` is created in the working directory. Incoming data is written to the table `cars`. -block CarsLoader oftype SQLiteLoader { - table: "cars"; - file: "./cars.db"; -} -*/ -builtin blocktype SQLiteLoader { - input default oftype Table; - output default oftype None; - - // The name of the table to write into. - property table oftype text; - // The path to a SQLite file that will be created if it does not exist. Usual file extensions are `.sqlite` and `.db`. - property file oftype text; - // Indicates, whether to drop the table before loading data into it. If `false`, data is appended to the table instead of dropping it. - property dropTable oftype boolean; -} - -/* -Extracts a `File` from the web. - -@example Fetches a file from the given URL. -block CarsFileExtractor oftype HttpExtractor { - url: "tinyurl.com/4ub9spwz"; -} -*/ -builtin blocktype HttpExtractor { - input default oftype None; - output default oftype File; - - // The URL to the file in the web to extract. - property url oftype text; - // Configures how many retries should be executed after a failure fetching the data. - property retries oftype integer; - // Configures the wait time in milliseconds before executing a retry. - property retryBackoffMilliseconds oftype integer; - // Configures the wait strategy before executing a retry. Can have values "exponential" or "linear". - property retryBackoffStrategy oftype text; - // Indicates, whether to follow redirects on get requests. If `false`, redirects are not followed. Default `true` - property followRedirects oftype boolean; -} - -/* -Interprets a `File` as a `TextFile`. -*/ -builtin blocktype TextFileInterpreter { - input default oftype File; - output default oftype TextFile; - - // The encoding used for decoding the file contents. - property encoding oftype text; - // The regex for identifying line breaks. - property lineBreak oftype Regex; -} - -/* -Selects a range of lines from a `TextFile`. -*/ -builtin blocktype TextRangeSelector { - input default oftype TextFile; - output default oftype TextFile; - - property lineFrom oftype integer; - property lineTo oftype integer; -} - -/* -Deletes individual lines from a `TextFile`. -*/ -builtin blocktype TextLineDeleter { - input default oftype TextFile; - output default oftype TextFile; - - // The line numbers to delete. - property lines oftype Collection; -} - -/* -Interprets a `File` as an archive file and converts it to a `FileSystem`. The archive file root is considered the root of the `FileSystem`. - -@example Interprets a `File` as a ZIP-archive and creates a `FileSystem` of its extracted contents. -block ZipArchiveInterpreter oftype ArchiveInterpreter { - archiveType: "zip"; -} -*/ -builtin blocktype ArchiveInterpreter { - input default oftype File; - output default oftype FileSystem; - - // The archive type to be interpreted, e.g., "zip" or "gz". - property archiveType oftype text; -} - -/* -Selects one `File` from a `FileSystem` based on its relative path to the root of the `FileSystem`. If no file matches the relative path, no output is created and the execution of the pipeline is aborted. - -@example Tries to pick the file `agency.txt` from the root of the provided `FileSystem`. If `agency.txt` exists it is passed on as `File`, if it does not exist the execution of the pipeline is aborted. -block AgencyFilePicker oftype FilePicker { - path: "./agency.txt"; -} -*/ -builtin blocktype FilePicker { - input default oftype FileSystem; - output default oftype File; - - // The path of the file to select, relative to the root of the provided `FileSystem`. - property path oftype text; -} - -/* -Interprets an protobuf file (binary) of type `File` by decoding the file according to `gtfs-realtime.proto`. Outputs the extracted entity defined by `entity` as a `Sheet` - -@example A file is interpretet as an GTFS-RT file, which contains TripUpdate. -block GtfsRTTripUpdateInterpreter oftype GtfsRTInterpreter{ - entity: "trip_update"; -} -*/ -builtin blocktype GtfsRTInterpreter { - input default oftype File; - output default oftype Sheet; - - // Entity to process from GTFS-RT-feed (`trip_update`, `alert` or `vehicle`). - // We currently support following Output-Sheets, each are an equivalent to the flattened Element Index defined in (just required fields are included)): - // - // Entity TripUpdate: - // ``` - // [ - // 'header.gtfs_realtime_version', - // 'header.timestamp', - // 'header.incrementality', - // 'entity.id', - // 'entity.trip_update.trip.trip_id', - // 'entity.trip_update.trip.route_id', - // 'entity.trip_update.stop_time_update.stop_sequence', - // 'entity.trip_update.stop_time_update.stop_id', - // 'entity.trip_update.stop_time_update.arrival.time', - // 'entity.trip_update.stop_time_update.departure.time', - // ]; - // - // ``` - // Entity VehiclePosition: - // ``` - // [ - // 'header.gtfs_realtime_version', - // 'header.timestamp', - // 'header.incrementality', - // 'entity.id', - // 'entity.vehicle_position.vehicle_descriptor.id', - // 'entity.vehicle_position.trip.trip_id', - // 'entity.vehicle_position.trip.route_id', - // 'entity.vehicle_position.position.latitude', - // 'entity.vehicle_position.position.longitude', - // 'entity.vehicle_position.timestamp', - // ]; - // ``` - // - // Entity Alert: - // ``` - // [ - // 'header.gtfs_realtime_version', - // 'header.timestamp', - // 'header.incrementality', - // 'entity.id', - // 'entity.alert.informed_entity.route_id', - // 'entity.alert.header_text', - // 'entity.alert.description_text', - // ]; - // ``` - // - // - property entity oftype text; -} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv new file mode 100644 index 000000000..14c836897 --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv @@ -0,0 +1,22 @@ +/* +Interprets a `File` as an archive file and converts it to a `FileSystem`. The archive file root is considered the root of the `FileSystem`. + +@example Interprets a `File` as a ZIP-archive and creates a `FileSystem` of its extracted contents. +block ZipArchiveInterpreter oftype ArchiveInterpreter { + archiveType: "zip"; +} +*/ +builtin blocktype ArchiveInterpreter { + input default oftype File; + output default oftype FileSystem; + + // The archive type to be interpreted, e.g., "zip" or "gz". + property archiveType oftype ArchiveType; // TODO: supported archive types +} + +valuetype ArchiveType { + constraints: [ArchiveTypeHandleConstraint]; +} + +constraint ArchiveTypeHandleConstraint on text: + value in ["zip", "gz"]; \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv new file mode 100644 index 000000000..2f8ddd5eb --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv @@ -0,0 +1,15 @@ +/* +Selects a subset of a `Sheet` to produce a new `Sheet`. + +@example Selects the cells in the given range and produces a new `Sheet` containing only the selected cells. +block CarsCoreDataSelector oftype CellRangeSelector { + select: range A1:E*; +} +*/ +builtin blocktype CellRangeSelector { + input default oftype Sheet; + output default oftype Sheet; + + // The cell range to select. + property select oftype CellRange; +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv new file mode 100644 index 000000000..aea96ccb6 --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv @@ -0,0 +1,25 @@ +/* +Writes textual values into cells of a `Sheet`. The number of text values needs to match the number of cells to write into. + +@example Write the value "Name" into cell `A1`. +block NameHeaderWriter oftype CellWriter { + at: cell A1; + write: ["Name"]; +} + +@example Write the values "Name", "Age" into cells `A1` and `A2`. +block HeaderSequenceWriter oftype CellWriter { + at: range A1:A2; + write: ["Name", "Age"]; +} +*/ +builtin blocktype CellWriter { + input default oftype Sheet; + output default oftype Sheet; + + // The values to write. + property write oftype Collection; + // The cells to write into. + property at oftype CellRange; // TODO: ensure 1-dimensional + // TODO: ensure write.length === at.dim +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv new file mode 100644 index 000000000..89bdfd4d4 --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv @@ -0,0 +1,15 @@ +/* +Deletes columns from a `Sheet`. Column IDs of subsequent columns will be shifted accordingly, so there will be no gaps. + +@example Deletes column B (i.e. the second column). +block MpgColumnDeleter oftype ColumnDeleter { + delete: [column B]; +} +*/ +builtin blocktype ColumnDeleter { + input default oftype Sheet; + output default oftype Sheet; + + // The columns to delete. + property delete oftype Collection; // TODO: ensure whole column is selected +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv new file mode 100644 index 000000000..8f2337c4e --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv @@ -0,0 +1,19 @@ +/* +Interprets an input file as a csv-file containing string-values delimited by `delimiter` and outputs a `Sheet`. + +@example Interprets an input file as a csv-file containing string-values delimited by `;` and outputs `Sheet`. +block AgencyCSVInterpreter oftype CSVInterpreter { + delimiter: ";"; + } +*/ +builtin blocktype CSVInterpreter { + input default oftype TextFile; + output default oftype Sheet; + + // The delimiter for values in the CSV file. + property delimiter oftype text: ','; + // The enclosing character that may be used for values in the CSV file. + property enclosing oftype text: ''; + // The character to escape enclosing characters in values. + property enclosingEscape oftype text: ''; +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv b/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv new file mode 100644 index 000000000..4cb18c9ce --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv @@ -0,0 +1,15 @@ +/* +Selects one `File` from a `FileSystem` based on its relative path to the root of the `FileSystem`. If no file matches the relative path, no output is created and the execution of the pipeline is aborted. + +@example Tries to pick the file `agency.txt` from the root of the provided `FileSystem`. If `agency.txt` exists it is passed on as `File`, if it does not exist the execution of the pipeline is aborted. +block AgencyFilePicker oftype FilePicker { + path: "./agency.txt"; +} +*/ +builtin blocktype FilePicker { + input default oftype FileSystem; + output default oftype File; + + // The path of the file to select, relative to the root of the provided `FileSystem`. + property path oftype text; +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv new file mode 100644 index 000000000..61f765f0b --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv @@ -0,0 +1,70 @@ +/* +Interprets an protobuf file (binary) of type `File` by decoding the file according to `gtfs-realtime.proto`. Outputs the extracted entity defined by `entity` as a `Sheet` + +@example A file is interpretet as an GTFS-RT file, which contains TripUpdate. +block GtfsRTTripUpdateInterpreter oftype GtfsRTInterpreter{ + entity: "trip_update"; +} +*/ +builtin blocktype GtfsRTInterpreter { + input default oftype File; + output default oftype Sheet; + + // Entity to process from GTFS-RT-feed (`trip_update`, `alert` or `vehicle`). + // We currently support following Output-Sheets, each are an equivalent to the flattened Element Index defined in (just required fields are included)): + // + // Entity TripUpdate: + // ``` + // [ + // 'header.gtfs_realtime_version', + // 'header.timestamp', + // 'header.incrementality', + // 'entity.id', + // 'entity.trip_update.trip.trip_id', + // 'entity.trip_update.trip.route_id', + // 'entity.trip_update.stop_time_update.stop_sequence', + // 'entity.trip_update.stop_time_update.stop_id', + // 'entity.trip_update.stop_time_update.arrival.time', + // 'entity.trip_update.stop_time_update.departure.time', + // ]; + // + // ``` + // Entity VehiclePosition: + // ``` + // [ + // 'header.gtfs_realtime_version', + // 'header.timestamp', + // 'header.incrementality', + // 'entity.id', + // 'entity.vehicle_position.vehicle_descriptor.id', + // 'entity.vehicle_position.trip.trip_id', + // 'entity.vehicle_position.trip.route_id', + // 'entity.vehicle_position.position.latitude', + // 'entity.vehicle_position.position.longitude', + // 'entity.vehicle_position.timestamp', + // ]; + // ``` + // + // Entity Alert: + // ``` + // [ + // 'header.gtfs_realtime_version', + // 'header.timestamp', + // 'header.incrementality', + // 'entity.id', + // 'entity.alert.informed_entity.route_id', + // 'entity.alert.header_text', + // 'entity.alert.description_text', + // ]; + // ``` + // + // + property entity oftype GtfsRTEntity; +} + +valuetype GtfsRTEntity { + constraints: [GtfsRTEntityConstraint]; +} + +constraint GtfsRTEntityConstraint on text: + value in ['trip_update', 'alert', 'vehicle']; \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv new file mode 100644 index 000000000..21adc1043 --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv @@ -0,0 +1,45 @@ +/* +Extracts a `File` from the web. + +@example Fetches a file from the given URL. +block CarsFileExtractor oftype HttpExtractor { + url: "tinyurl.com/4ub9spwz"; +} +*/ +builtin blocktype HttpExtractor { + input default oftype None; + output default oftype File; + + // The URL to the file in the web to extract. + property url oftype text; + // Configures how many retries should be executed after a failure fetching the data. + property retries oftype Count: 0; + // Configures the wait time in milliseconds before executing a retry. + property retryBackoffMilliseconds oftype RetryIntervalMilliseconds: 1000; + // Configures the wait strategy before executing a retry. Can have values "exponential" or "linear". + property retryBackoffStrategy oftype RetryBackoffStrategy: "exponential"; + // Indicates, whether to follow redirects on get requests. If `false`, redirects are not followed. Default `true` + property followRedirects oftype boolean: true; +} + +valuetype Count { + constraints: [IntNonNegative]; +} + +constraint IntNonNegative on integer: + value >= 0; + +valuetype RetryIntervalMilliseconds { + constraints: [IntOver999]; +} + +constraint IntOver999 on integer: + value > 999; + +valuetype RetryBackoffStrategy { + constraints : [RetryBackoffStrategyConstraint] +} + +constraint RetryBackoffStrategyConstraint on text: + value in ["linear", "exponential"]; + diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv b/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv new file mode 100644 index 000000000..ca41e29aa --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv @@ -0,0 +1,30 @@ +/* +Loads a `Table` into a PostgreSQL database sink. + +@example A local Postgres instance is filled with table data about cars. +block CarsLoader oftype PostgresLoader { + host: "localhost"; + port: 5432; + username: "postgres"; + password: "postgres"; + database: "CarsDB"; + table: "Cars"; +} +*/ +builtin blocktype PostgresLoader { + input default oftype Table; + output default oftype None; + + // The hostname or IP address of the Postgres database. + property host oftype text; + // The port of the Postgres database. + property port oftype integer; + // The username to login to the Postgres database. + property username oftype text; + // The password to login to the Postgres database. + property password oftype text; + // The database to use. + property database oftype text; + // The name of the table to write into. + property table oftype text; +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv new file mode 100644 index 000000000..e94e5a75a --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv @@ -0,0 +1,15 @@ +/* +Deletes one or more rows from a `Sheet`. Row IDs of subsequent rows will be shifted accordingly, so there will be no gaps. + +@example Deletes row 2 (i.e. the second row). +block SecondRowDeleter oftype RowDeleter { + delete: [row 2]; +} +*/ +builtin blocktype RowDeleter { + input default oftype Sheet; + output default oftype Sheet; + + // The rows to delete. + property delete oftype Collection; // TODO: ensure whole row is selected +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv b/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv new file mode 100644 index 000000000..28022d5c7 --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv @@ -0,0 +1,15 @@ +/* +Selects one `Sheet` from a `Workbook` based on its `sheetName`. If no sheet matches the name, no output is created and the execution of the pipeline is aborted. + +@example Tries to pick the sheet `AgencyNames` from the provided `Workbook`. If `AgencyNames` exists it is passed on as `Sheet`, if it does not exist the execution of the pipeline is aborted. +block AgencySheetPicker oftype SheetPicker { + sheetName: "AgencyNames"; +} +*/ +builtin blocktype SheetPicker { + input default oftype Workbook; + output default oftype Sheet; + + // The name of the sheet to select. + property sheetName oftype text; +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv b/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv new file mode 100644 index 000000000..477b3fb78 --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv @@ -0,0 +1,20 @@ +/* +Loads a `Table` into a SQLite database sink. + +@example A SQLite file `cars.db` is created in the working directory. Incoming data is written to the table `cars`. +block CarsLoader oftype SQLiteLoader { + table: "cars"; + file: "./cars.db"; +} +*/ +builtin blocktype SQLiteLoader { + input default oftype Table; + output default oftype None; + + // The name of the table to write into. + property table oftype text; + // The path to a SQLite file that will be created if it does not exist. Usual file extensions are `.sqlite` and `.db`. + property file oftype text; + // Indicates, whether to drop the table before loading data into it. If `false`, data is appended to the table instead of dropping it. + property dropTable oftype boolean: true; +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv new file mode 100644 index 000000000..4f79ac284 --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv @@ -0,0 +1,32 @@ +/* +Interprets a `Sheet` as a `Table`. In case a header row is present in the sheet, its names can be matched with the provided column names. Otherwise, the provided column names are assigned in order. + +@example Interprets a `Sheet` about cars with a topmost header row and interprets it as a `Table` by assigning a primitive valuetype to each column. The column names are matched to the header, so the order of the type assignments does not matter. +block CarsTableInterpreter oftype TableInterpreter { + header: true; + columns: [ + "name" oftype text, + "mpg" oftype decimal, + "cyl" oftype integer, + ]; +} + +@example Interprets a `Sheet` about cars without a topmost header row and interprets it as a `Table` by sequentially assigning a name and a primitive valuetype to each column of the sheet. Note that the order of columns matters here. The first column (column `A`) will be named "name", the second column (column `B`) will be named "mpg" etc. +block CarsTableInterpreter oftype TableInterpreter { + header: false; + columns: [ + "name" oftype text, + "mpg" oftype decimal, + "cyl" oftype integer, + ]; +} +*/ +builtin blocktype TableInterpreter { + input default oftype Sheet; + output default oftype Table; + + // Whether the first row should be interpreted as header row. + property header oftype boolean: true; + // Collection of valuetype assignments. Uses column names (potentially matched with the header or by sequence depending on the `header` property) to assign a primitive valuetype to each column. + property columns oftype Collection; // TODO: ensure unique names +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv new file mode 100644 index 000000000..1676c7c59 --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv @@ -0,0 +1,45 @@ +/* +Applies a transform on each value of a column. The input port type of the used transform has to match the type of the input column. + +@example Given a column "temperature" with temperature values in Celsius, it overwrites the column with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model. + +transform CelsiusToFahrenheit { + from Celsius oftype decimal; + to Fahrenheit oftype decimal; + + Fahrenheit: (Celsius * 9/5) + 32; +} + +block CelsiusToFahrenheitTransformer oftype TableTransformer { + inputColumns: ['temperature']; + outputColumn: 'temperature'; + use: CelsiusToFahrenheit; +} + +@example Given a column "temperatureCelsius" with temperature values in Celsius, it adds a new column "temperatureFahrenheit" with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model. + +transform CelsiusToFahrenheit { + from Celsius oftype decimal; + to Fahrenheit oftype decimal; + + Fahrenheit: (Celsius * 9/5) + 32; +} + +block CelsiusToFahrenheitTransformer oftype TableTransformer { + inputColumns: ['temperatureCelsius']; + outputColumn: 'temperatureFahrenheit'; + use: CelsiusToFahrenheit; +} +*/ +builtin blocktype TableTransformer { + input default oftype Table; + output default oftype Table; + + // The names of the input columns. The columns have to be present in the table and match with the transform's input port types. + property inputColumns oftype Collection; + // The name of the output column. Overwrites the column if it already exists, or otherwise creates a new one. + property outputColumn oftype text; + // Reference to the transform that is applied to the column. + property use oftype Transform; + // TODO: checkInputColumnsMatchTransformationPorts +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv new file mode 100644 index 000000000..04cbc5401 --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv @@ -0,0 +1,21 @@ +/* +Interprets a `File` as a `TextFile`. +*/ +builtin blocktype TextFileInterpreter { + input default oftype File; + output default oftype TextFile; + + // The encoding used for decoding the file contents. + property encoding oftype TextEncoding: 'utf-8'; + // The regex for identifying line breaks. + property lineBreak oftype Regex: /\r?\n/; + // TODO: check Regex valuetype +} + +valuetype TextEncoding { + constraints: [TextEncodingConstraint]; +} + +constraint TextEncodingConstraint on text: + // https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API/Encodings + value in ['utf-8', 'ibm866', 'latin2', 'latin3', 'latin4', 'cyrillic', 'arabic', 'greek', 'hebrew', 'logical', 'latin6', 'utf-16']; diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv new file mode 100644 index 000000000..2868184cd --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv @@ -0,0 +1,17 @@ +/* +Deletes individual lines from a `TextFile`. +*/ +builtin blocktype TextLineDeleter { + input default oftype TextFile; + output default oftype TextFile; + + // The line numbers to delete. + property lines oftype Collection; +} + +valuetype TextLine { + constraints: [PositiveIntConstraint]; +} + +constraint PositiveIntConstraint on integer: + value > 0; \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv new file mode 100644 index 000000000..f71724f28 --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv @@ -0,0 +1,11 @@ +/* +Selects a range of lines from a `TextFile`. +*/ +builtin blocktype TextRangeSelector { + input default oftype TextFile; + output default oftype TextFile; + + property lineFrom oftype integer: 1; + property lineTo oftype integer: 999999; // TODO: allow sth like +Infinity + // TODO: ensure lineFrom <= lineTo +} \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv new file mode 100644 index 000000000..c74e6ade6 --- /dev/null +++ b/libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv @@ -0,0 +1,11 @@ +/* +Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s. + +@example Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s. +block AgencyXLSXInterpreter oftype XLSXInterpreter { + } +*/ +builtin blocktype XLSXInterpreter { + input default oftype File; + output default oftype Workbook; +} \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json index c164052d5..efd1f64e5 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -32,24 +32,15 @@ "@jvalue/jayvee-extensions/rdbms/test": [ "libs/extensions/rdbms/exec/test/index.ts" ], - "@jvalue/jayvee-extensions/rdbms/lang": [ - "libs/extensions/rdbms/lang/src/index.ts" - ], "@jvalue/jayvee-extensions/std/exec": [ "libs/extensions/std/exec/src/index.ts" ], "@jvalue/jayvee-extensions/std/test": [ "libs/extensions/std/exec/test/index.ts" ], - "@jvalue/jayvee-extensions/std/lang": [ - "libs/extensions/std/lang/src/index.ts" - ], "@jvalue/jayvee-extensions/tabular/exec": [ "libs/extensions/tabular/exec/src/index.ts" ], - "@jvalue/jayvee-extensions/tabular/lang": [ - "libs/extensions/tabular/lang/src/index.ts" - ], "@jvalue/jayvee-language-server": ["libs/language-server/src/index.ts"], "@jvalue/jayvee-language-server/test": [ "libs/language-server/src/test/index.ts" From 249c8563d5ef051cbc946bc244cfb5d56b4b8eea Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 5 Sep 2023 14:00:56 +0200 Subject: [PATCH 06/43] Fix build and linter of remaining apps/libs --- apps/docs/generator/src/main.ts | 8 ++------ apps/language-server-web-worker/src/main.ts | 8 +------- .../executors/allowlist-constraint-executor.spec.ts | 4 ---- .../executors/denylist-constraint-executor.spec.ts | 4 ---- .../executors/expression-constraint-executor.spec.ts | 4 ---- .../executors/length-constraint-executor.spec.ts | 4 ---- .../executors/range-constraint-executor.spec.ts | 4 ---- .../executors/regex-constraint-executor.spec.ts | 4 ---- libs/interpreter-lib/src/std-extension.spec.ts | 5 +++-- .../src/lib/validation/checks/property-assignment.ts | 4 +++- .../src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv | 2 +- .../src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv | 2 +- .../src/stdlib/builtin-blocktypes/HttpExtractor.jv | 6 +++--- .../src/stdlib/builtin-blocktypes/TextFileInterpreter.jv | 2 +- .../src/stdlib/builtin-blocktypes/TextLineDeleter.jv | 2 +- libs/language-server/src/test/utils.ts | 3 +-- 16 files changed, 17 insertions(+), 49 deletions(-) diff --git a/apps/docs/generator/src/main.ts b/apps/docs/generator/src/main.ts index 742e85768..de7cdaa41 100644 --- a/apps/docs/generator/src/main.ts +++ b/apps/docs/generator/src/main.ts @@ -5,19 +5,15 @@ import { readFileSync, readdirSync, writeFileSync } from 'fs'; import { join } from 'path'; -import { StdLangExtension } from '@jvalue/jayvee-extensions/std/lang'; import { + BlockMetaInformation, PrimitiveValuetypes, - getRegisteredBlockMetaInformation, getRegisteredConstraintMetaInformation, registerConstraints, - useExtension, } from '@jvalue/jayvee-language-server'; import { UserDocGenerator } from './user-doc-generator'; -useExtension(new StdLangExtension()); - function main(): void { const rootPath = join(__dirname, '..', '..', '..', '..'); generateBlockTypeDocs(rootPath); @@ -35,7 +31,7 @@ function generateBlockTypeDocs(rootPath: string): void { 'user', 'block-types', ); - const metaInfs = getRegisteredBlockMetaInformation(); + const metaInfs: BlockMetaInformation[] = []; // TODO: load from Std Lib for (const metaInf of metaInfs) { const userDocBuilder = new UserDocGenerator(); const blockTypeDoc = userDocBuilder.generateBlockTypeDoc(metaInf); diff --git a/apps/language-server-web-worker/src/main.ts b/apps/language-server-web-worker/src/main.ts index d25a67be3..44d09d6b1 100644 --- a/apps/language-server-web-worker/src/main.ts +++ b/apps/language-server-web-worker/src/main.ts @@ -2,11 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { StdLangExtension } from '@jvalue/jayvee-extensions/std/lang'; -import { - createJayveeServices, - useExtension, -} from '@jvalue/jayvee-language-server'; +import { createJayveeServices } from '@jvalue/jayvee-language-server'; import { EmptyFileSystem, startLanguageServer } from 'langium'; import { BrowserMessageReader, @@ -21,8 +17,6 @@ const messageWriter = new BrowserMessageWriter(self); const connection = createConnection(messageReader, messageWriter); -useExtension(new StdLangExtension()); - const { shared } = createJayveeServices({ connection, ...EmptyFileSystem }); startLanguageServer(shared); diff --git a/libs/execution/src/lib/constraints/executors/allowlist-constraint-executor.spec.ts b/libs/execution/src/lib/constraints/executors/allowlist-constraint-executor.spec.ts index 65f8bcfb5..d4693a9f8 100644 --- a/libs/execution/src/lib/constraints/executors/allowlist-constraint-executor.spec.ts +++ b/libs/execution/src/lib/constraints/executors/allowlist-constraint-executor.spec.ts @@ -7,11 +7,9 @@ import { InternalValueRepresentation, TypedConstraintDefinition, createJayveeServices, - useExtension, } from '@jvalue/jayvee-language-server'; import { ParseHelperOptions, - TestLangExtension, expectNoParserAndLexerErrors, parseHelper, readJvTestAssetHelper, @@ -60,8 +58,6 @@ describe('Validation of AllowlistConstraintExecutor', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/execution/src/lib/constraints/executors/denylist-constraint-executor.spec.ts b/libs/execution/src/lib/constraints/executors/denylist-constraint-executor.spec.ts index 7957320fe..0f8d4d922 100644 --- a/libs/execution/src/lib/constraints/executors/denylist-constraint-executor.spec.ts +++ b/libs/execution/src/lib/constraints/executors/denylist-constraint-executor.spec.ts @@ -7,11 +7,9 @@ import { InternalValueRepresentation, TypedConstraintDefinition, createJayveeServices, - useExtension, } from '@jvalue/jayvee-language-server'; import { ParseHelperOptions, - TestLangExtension, expectNoParserAndLexerErrors, parseHelper, readJvTestAssetHelper, @@ -60,8 +58,6 @@ describe('Validation of DenylistConstraintExecutor', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/execution/src/lib/constraints/executors/expression-constraint-executor.spec.ts b/libs/execution/src/lib/constraints/executors/expression-constraint-executor.spec.ts index bfd81e6b9..64977c0f8 100644 --- a/libs/execution/src/lib/constraints/executors/expression-constraint-executor.spec.ts +++ b/libs/execution/src/lib/constraints/executors/expression-constraint-executor.spec.ts @@ -7,11 +7,9 @@ import { ExpressionConstraintDefinition, InternalValueRepresentation, createJayveeServices, - useExtension, } from '@jvalue/jayvee-language-server'; import { ParseHelperOptions, - TestLangExtension, expectNoParserAndLexerErrors, parseHelper, readJvTestAssetHelper, @@ -60,8 +58,6 @@ describe('Validation of AllowlistConstraintExecutor', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/execution/src/lib/constraints/executors/length-constraint-executor.spec.ts b/libs/execution/src/lib/constraints/executors/length-constraint-executor.spec.ts index 28cdc3df2..68b9442c3 100644 --- a/libs/execution/src/lib/constraints/executors/length-constraint-executor.spec.ts +++ b/libs/execution/src/lib/constraints/executors/length-constraint-executor.spec.ts @@ -7,11 +7,9 @@ import { InternalValueRepresentation, TypedConstraintDefinition, createJayveeServices, - useExtension, } from '@jvalue/jayvee-language-server'; import { ParseHelperOptions, - TestLangExtension, expectNoParserAndLexerErrors, parseHelper, readJvTestAssetHelper, @@ -60,8 +58,6 @@ describe('Validation of LengthConstraintExecutor', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/execution/src/lib/constraints/executors/range-constraint-executor.spec.ts b/libs/execution/src/lib/constraints/executors/range-constraint-executor.spec.ts index e0bd6550a..20115e541 100644 --- a/libs/execution/src/lib/constraints/executors/range-constraint-executor.spec.ts +++ b/libs/execution/src/lib/constraints/executors/range-constraint-executor.spec.ts @@ -7,11 +7,9 @@ import { InternalValueRepresentation, TypedConstraintDefinition, createJayveeServices, - useExtension, } from '@jvalue/jayvee-language-server'; import { ParseHelperOptions, - TestLangExtension, expectNoParserAndLexerErrors, parseHelper, readJvTestAssetHelper, @@ -60,8 +58,6 @@ describe('Validation of RangeConstraintExecutor', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/execution/src/lib/constraints/executors/regex-constraint-executor.spec.ts b/libs/execution/src/lib/constraints/executors/regex-constraint-executor.spec.ts index 77e38f1ec..09e83970b 100644 --- a/libs/execution/src/lib/constraints/executors/regex-constraint-executor.spec.ts +++ b/libs/execution/src/lib/constraints/executors/regex-constraint-executor.spec.ts @@ -7,11 +7,9 @@ import { InternalValueRepresentation, TypedConstraintDefinition, createJayveeServices, - useExtension, } from '@jvalue/jayvee-language-server'; import { ParseHelperOptions, - TestLangExtension, expectNoParserAndLexerErrors, parseHelper, readJvTestAssetHelper, @@ -60,8 +58,6 @@ describe('Validation of RegexConstraintExecutor', () => { } beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/interpreter-lib/src/std-extension.spec.ts b/libs/interpreter-lib/src/std-extension.spec.ts index abfe4b562..958679fd0 100644 --- a/libs/interpreter-lib/src/std-extension.spec.ts +++ b/libs/interpreter-lib/src/std-extension.spec.ts @@ -5,13 +5,14 @@ import { strict as assert } from 'assert'; import { getRegisteredBlockExecutors } from '@jvalue/jayvee-execution'; -import { getRegisteredBlockMetaInformation } from '@jvalue/jayvee-language-server'; +import { BlockMetaInformation } from '@jvalue/jayvee-language-server'; import { useStdExtension } from './interpreter'; describe('std extension', () => { useStdExtension(); - getRegisteredBlockMetaInformation().forEach((metaInf) => { + [].forEach((metaInf: BlockMetaInformation) => { + // TODO: iterate over all block meta inf it(`should provide a matching block executor for block type ${metaInf.type}`, () => { const matchingBlockExecutorClass = getRegisteredBlockExecutors().find( (blockExecutorClass) => blockExecutorClass.type === metaInf.type, diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index 0f3e8b032..88b360d64 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -95,7 +95,9 @@ function checkPropertyValueTyping( if (!inferredType.isConvertibleTo(propertyType)) { validationContext.accept( 'error', - `The value needs to be of type ${propertyType.getName()} but is of type ${inferredType.getName()}`, + `The value of property "${ + property.name + }" needs to be of type ${propertyType.getName()} but is of type ${inferredType.getName()}`, { node: propertyValue, }, diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv index 14c836897..b705a895e 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv @@ -14,7 +14,7 @@ builtin blocktype ArchiveInterpreter { property archiveType oftype ArchiveType; // TODO: supported archive types } -valuetype ArchiveType { +valuetype ArchiveType oftype text { constraints: [ArchiveTypeHandleConstraint]; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv index 61f765f0b..d07be5f1a 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv @@ -62,7 +62,7 @@ builtin blocktype GtfsRTInterpreter { property entity oftype GtfsRTEntity; } -valuetype GtfsRTEntity { +valuetype GtfsRTEntity oftype text { constraints: [GtfsRTEntityConstraint]; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv index 21adc1043..42ab7f3c0 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv @@ -22,21 +22,21 @@ builtin blocktype HttpExtractor { property followRedirects oftype boolean: true; } -valuetype Count { +valuetype Count oftype integer { constraints: [IntNonNegative]; } constraint IntNonNegative on integer: value >= 0; -valuetype RetryIntervalMilliseconds { +valuetype RetryIntervalMilliseconds oftype integer { constraints: [IntOver999]; } constraint IntOver999 on integer: value > 999; -valuetype RetryBackoffStrategy { +valuetype RetryBackoffStrategy oftype text { constraints : [RetryBackoffStrategyConstraint] } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv index 04cbc5401..1f23ff278 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv @@ -12,7 +12,7 @@ builtin blocktype TextFileInterpreter { // TODO: check Regex valuetype } -valuetype TextEncoding { +valuetype TextEncoding oftype text { constraints: [TextEncodingConstraint]; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv index 2868184cd..0dca2ce41 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv @@ -9,7 +9,7 @@ builtin blocktype TextLineDeleter { property lines oftype Collection; } -valuetype TextLine { +valuetype TextLine oftype integer { constraints: [PositiveIntConstraint]; } diff --git a/libs/language-server/src/test/utils.ts b/libs/language-server/src/test/utils.ts index 2310e2c6c..c5c9e72e9 100644 --- a/libs/language-server/src/test/utils.ts +++ b/libs/language-server/src/test/utils.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import { AstNode, LangiumDocument, ValidationAcceptor } from 'langium'; -import { blockMetaInfRegistry, constraintMetaInfRegistry } from '../lib'; +import { constraintMetaInfRegistry } from '../lib/meta-information/meta-inf-registry'; // eslint-disable-next-line @typescript-eslint/no-empty-function export const validationAcceptorMockImpl: ValidationAcceptor = () => {}; @@ -44,6 +44,5 @@ export function expectNoParserAndLexerErrors( } export function clearMetaInfRegistry() { - blockMetaInfRegistry.clear(); constraintMetaInfRegistry.clear(); } From 8f9da7e2a4fd3d4abd566018daa0ad5870c83078 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 5 Sep 2023 15:05:36 +0200 Subject: [PATCH 07/43] Remove test.jv --- example/test.jv | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 example/test.jv diff --git a/example/test.jv b/example/test.jv deleted file mode 100644 index 8f2337c4e..000000000 --- a/example/test.jv +++ /dev/null @@ -1,19 +0,0 @@ -/* -Interprets an input file as a csv-file containing string-values delimited by `delimiter` and outputs a `Sheet`. - -@example Interprets an input file as a csv-file containing string-values delimited by `;` and outputs `Sheet`. -block AgencyCSVInterpreter oftype CSVInterpreter { - delimiter: ";"; - } -*/ -builtin blocktype CSVInterpreter { - input default oftype TextFile; - output default oftype Sheet; - - // The delimiter for values in the CSV file. - property delimiter oftype text: ','; - // The enclosing character that may be used for values in the CSV file. - property enclosing oftype text: ''; - // The character to escape enclosing characters in values. - property enclosingEscape oftype text: ''; -} \ No newline at end of file From 27d62f1c51518cd86d39770aa64b4c3126012452 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 5 Sep 2023 16:25:03 +0200 Subject: [PATCH 08/43] Move validations from ArchiveInterpreter to property assignment validations --- .../checks/property-assignment.spec.ts | 2 +- .../validation/checks/property-assignment.ts | 64 ++++++++++++++++++- .../builtin-blocktypes/ArchiveInterpreter.jv | 9 +-- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index 9a9ec44c6..fe4079c55 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -139,7 +139,7 @@ describe('Validation of PropertyAssignment', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(1); expect(validationAcceptorMock).toHaveBeenCalledWith( 'error', - `The value needs to be of type text but is of type integer`, + `The value of property "textProperty" needs to be of type text but is of type integer`, expect.any(Object), ); }); diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index 88b360d64..9639d2ca9 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -7,7 +7,12 @@ */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ -import { EvaluationContext, inferExpressionType } from '../../ast'; +import { + EvaluationContext, + InternalValueRepresentation, + evaluatePropertyValue, + inferExpressionType, +} from '../../ast'; import { PropertyAssignment, isBlocktypeProperty, @@ -39,6 +44,13 @@ export function validatePropertyAssignment( validationContext, evaluationContext, ); + + checkBlocktypeSpecificProperties( + property, + propertySpec, + validationContext, + evaluationContext, + ); } function checkPropertyNameValidity( @@ -111,3 +123,53 @@ function checkPropertyValueTyping( evaluationContext, ); } + +function checkBlocktypeSpecificProperties( + property: PropertyAssignment, + propertySpec: PropertySpecification, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + const propName = property.name; + const propValue = evaluatePropertyValue( + property, + evaluationContext, + propertySpec.type, + ); + if (propValue === undefined) { + return; + } + + switch (property.$container.$container.type.ref?.name) { + case 'ArchiveInterpreter': + return checkArchiveInterpreterProperties( + propName, + propValue, + property, + validationContext, + ); + default: + } +} + +function checkArchiveInterpreterProperties( + propName: string, + propValue: InternalValueRepresentation, + property: PropertyAssignment, + validationContext: ValidationContext, +) { + const allowedArchiveTypes: InternalValueRepresentation[] = ['zip', 'gz']; + if (propName === 'archiveType') { + if (!allowedArchiveTypes.includes(propValue)) { + validationContext.accept( + 'error', + `The value of property "${propName}" is not a valid value: [${allowedArchiveTypes.join( + ', ', + )}]`, + { + node: property, + }, + ); + } + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv index b705a895e..42d275fda 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv @@ -11,12 +11,5 @@ builtin blocktype ArchiveInterpreter { output default oftype FileSystem; // The archive type to be interpreted, e.g., "zip" or "gz". - property archiveType oftype ArchiveType; // TODO: supported archive types + property archiveType oftype text; } - -valuetype ArchiveType oftype text { - constraints: [ArchiveTypeHandleConstraint]; -} - -constraint ArchiveTypeHandleConstraint on text: - value in ["zip", "gz"]; \ No newline at end of file From 4f26f7d8b28061694d38bd9c2fb68240eb96d317 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 5 Sep 2023 17:05:13 +0200 Subject: [PATCH 09/43] Move validations from CellWriter to property assignment validations --- .../checks/property-assignment.spec.ts | 17 ++++++++ .../validation/checks/property-assignment.ts | 40 ++++++++++++++++++- .../stdlib/builtin-blocktypes/CellWriter.jv | 4 +- .../cell-writer/invalid-wrong-at-dimension.jv | 18 +++++++++ 4 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/cell-writer/invalid-wrong-at-dimension.jv diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index fe4079c55..540646843 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -181,4 +181,21 @@ describe('Validation of PropertyAssignment', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(0); }); + + describe('CellWriter blocktype', () => { + it('should diagnose error on wrong dimension for at parameter', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/cell-writer/invalid-wrong-at-dimension.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The cell range needs to be one-dimensional', + expect.any(Object), + ); + }); + }); }); diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index 9639d2ca9..606ecc090 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -10,6 +10,7 @@ import { EvaluationContext, InternalValueRepresentation, + PrimitiveValuetypes, evaluatePropertyValue, inferExpressionType, } from '../../ast'; @@ -142,17 +143,24 @@ function checkBlocktypeSpecificProperties( switch (property.$container.$container.type.ref?.name) { case 'ArchiveInterpreter': - return checkArchiveInterpreterProperties( + return checkArchiveInterpreterProperty( propName, propValue, property, validationContext, ); + case 'CellWriter': + return checkCellWriterProperty( + propName, + property, + validationContext, + evaluationContext, + ); default: } } -function checkArchiveInterpreterProperties( +function checkArchiveInterpreterProperty( propName: string, propValue: InternalValueRepresentation, property: PropertyAssignment, @@ -173,3 +181,31 @@ function checkArchiveInterpreterProperties( } } } + +function checkCellWriterProperty( + propName: string, + property: PropertyAssignment, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + if (propName === 'at') { + const cellRange = evaluatePropertyValue( + property, + evaluationContext, + PrimitiveValuetypes.CellRange, + ); + if (cellRange === undefined) { + return; + } + + if (!cellRange.isOneDimensional()) { + validationContext.accept( + 'error', + 'The cell range needs to be one-dimensional', + { + node: cellRange.astNode, + }, + ); + } + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv index aea96ccb6..fc7d41a0d 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv @@ -20,6 +20,6 @@ builtin blocktype CellWriter { // The values to write. property write oftype Collection; // The cells to write into. - property at oftype CellRange; // TODO: ensure 1-dimensional - // TODO: ensure write.length === at.dim + property at oftype CellRange; + // TODO: ensure write.length === at.values.length } \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/cell-writer/invalid-wrong-at-dimension.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/cell-writer/invalid-wrong-at-dimension.jv new file mode 100644 index 000000000..d8154bf76 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/cell-writer/invalid-wrong-at-dimension.jv @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype CellWriter { + at: range A1:B2; + write: ['the', 'values', 'to', 'write']; + } + + block TestExtractor oftype TestSheetExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} From 575cad48008043accad3b1a0580011747f862ac2 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 5 Sep 2023 17:13:32 +0200 Subject: [PATCH 10/43] Move validations from ColumnDeleter to property assignment validations --- .../checks/property-assignment.spec.ts | 27 ++++++++++++++ .../validation/checks/property-assignment.ts | 36 +++++++++++++++++++ .../builtin-blocktypes/ColumnDeleter.jv | 4 +-- .../invalid-partial-column-delete.jv | 17 +++++++++ .../column-deleter/valid-column-delete.jv | 17 +++++++++ 5 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/column-deleter/invalid-partial-column-delete.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/column-deleter/valid-column-delete.jv diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index 540646843..298d0d2c3 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -198,4 +198,31 @@ describe('Validation of PropertyAssignment', () => { ); }); }); + + describe('ColumnDeleter blocktype', () => { + it('should diagnose error on deleting partial column', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/column-deleter/invalid-partial-column-delete.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'An entire column needs to be selected', + expect.any(Object), + ); + }); + + it('should diagnose no error', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/column-deleter/valid-column-delete.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + }); }); diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index 606ecc090..f26f6c88b 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -8,11 +8,13 @@ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ import { + CollectionValuetype, EvaluationContext, InternalValueRepresentation, PrimitiveValuetypes, evaluatePropertyValue, inferExpressionType, + isColumnWrapper, } from '../../ast'; import { PropertyAssignment, @@ -156,6 +158,13 @@ function checkBlocktypeSpecificProperties( validationContext, evaluationContext, ); + case 'ColumnDeleter': + return checkColumnDeleterProperty( + propName, + property, + validationContext, + evaluationContext, + ); default: } } @@ -209,3 +218,30 @@ function checkCellWriterProperty( } } } + +function checkColumnDeleterProperty( + propName: string, + property: PropertyAssignment, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + if (propName === 'delete') { + const cellRanges = evaluatePropertyValue( + property, + evaluationContext, + new CollectionValuetype(PrimitiveValuetypes.CellRange), + ); + + cellRanges?.forEach((cellRange) => { + if (!isColumnWrapper(cellRange)) { + validationContext.accept( + 'error', + 'An entire column needs to be selected', + { + node: cellRange.astNode, + }, + ); + } + }); + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv index 89bdfd4d4..1733bb04c 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv @@ -10,6 +10,6 @@ builtin blocktype ColumnDeleter { input default oftype Sheet; output default oftype Sheet; - // The columns to delete. - property delete oftype Collection; // TODO: ensure whole column is selected + // The columns to delete. Has to be a full column. + property delete oftype Collection; } \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/column-deleter/invalid-partial-column-delete.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/column-deleter/invalid-partial-column-delete.jv new file mode 100644 index 000000000..981dab3ae --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/column-deleter/invalid-partial-column-delete.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype ColumnDeleter { + delete: [range A1:A3]; + } + + block TestExtractor oftype TestSheetExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/column-deleter/valid-column-delete.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/column-deleter/valid-column-delete.jv new file mode 100644 index 000000000..29da54be1 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/column-deleter/valid-column-delete.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype ColumnDeleter { + delete: [column A]; + } + + block TestExtractor oftype TestSheetExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} From 8e8c185f76e35d4974434d87076b7dc34491be11 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 5 Sep 2023 17:39:03 +0200 Subject: [PATCH 11/43] Move validations from GtfsRTInterpreter to property assignment validations --- .../checks/property-assignment.spec.ts | 27 +++++++++++++ .../validation/checks/property-assignment.ts | 39 +++++++++++++++++-- .../builtin-blocktypes/GtfsRtInterpreter.jv | 9 +---- .../invalid-invalid-entity-param.jv | 17 ++++++++ .../valid-valid-entity-param.jv | 17 ++++++++ 5 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/gtfs-rt-interpreter/invalid-invalid-entity-param.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/gtfs-rt-interpreter/valid-valid-entity-param.jv diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index 298d0d2c3..881c1b63d 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -225,4 +225,31 @@ describe('Validation of PropertyAssignment', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(0); }); }); + + describe('GtfsRTInterpreter blocktype', () => { + it('should diagnose no error on valid entity parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/gtfs-rt-interpreter/valid-valid-entity-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid entity parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/gtfs-rt-interpreter/invalid-invalid-entity-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "entity" must be one of the following values: "trip_update", "alert", "vehicle"', + expect.any(Object), + ); + }); + }); }); diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index f26f6c88b..658da2631 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -165,6 +165,13 @@ function checkBlocktypeSpecificProperties( validationContext, evaluationContext, ); + case 'GtfsRTInterpreter': + return checkGtfsRTInterpreterProperty( + propName, + propValue, + property, + validationContext, + ); default: } } @@ -180,9 +187,9 @@ function checkArchiveInterpreterProperty( if (!allowedArchiveTypes.includes(propValue)) { validationContext.accept( 'error', - `The value of property "${propName}" is not a valid value: [${allowedArchiveTypes.join( - ', ', - )}]`, + `The value of property "${propName}" must be one of the following values: ${allowedArchiveTypes + .map((v) => `"${v.toString()}"`) + .join(', ')}`, { node: property, }, @@ -245,3 +252,29 @@ function checkColumnDeleterProperty( }); } } + +function checkGtfsRTInterpreterProperty( + propName: string, + propValue: InternalValueRepresentation, + property: PropertyAssignment, + validationContext: ValidationContext, +) { + const allowedEntities: InternalValueRepresentation[] = [ + 'trip_update', + 'alert', + 'vehicle', + ]; + if (propName === 'entity') { + if (!allowedEntities.includes(propValue)) { + validationContext.accept( + 'error', + `The value of property "${propName}" must be one of the following values: ${allowedEntities + .map((v) => `"${v.toString()}"`) + .join(', ')}`, + { + node: property, + }, + ); + } + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv index d07be5f1a..62aa8d7b9 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv @@ -59,12 +59,5 @@ builtin blocktype GtfsRTInterpreter { // ``` // // - property entity oftype GtfsRTEntity; + property entity oftype text; } - -valuetype GtfsRTEntity oftype text { - constraints: [GtfsRTEntityConstraint]; -} - -constraint GtfsRTEntityConstraint on text: - value in ['trip_update', 'alert', 'vehicle']; \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/gtfs-rt-interpreter/invalid-invalid-entity-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/gtfs-rt-interpreter/invalid-invalid-entity-param.jv new file mode 100644 index 000000000..abcdd2705 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/gtfs-rt-interpreter/invalid-invalid-entity-param.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype GtfsRTInterpreter { + entity: 'invalid'; + } + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/gtfs-rt-interpreter/valid-valid-entity-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/gtfs-rt-interpreter/valid-valid-entity-param.jv new file mode 100644 index 000000000..98acd3a98 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/gtfs-rt-interpreter/valid-valid-entity-param.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype GtfsRTInterpreter { + entity: 'alert'; + } + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} From 4363920cfd53a31299a456074c51ca64179c3b7f Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 5 Sep 2023 17:43:02 +0200 Subject: [PATCH 12/43] Test ArchiveInterpreter custom validation --- .../checks/property-assignment.spec.ts | 27 +++++++++++++++++++ .../invalid-invalid-archivetype-param.jv | 17 ++++++++++++ .../valid-valid-archivetype-param.jv | 17 ++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/archive-interpreter/invalid-invalid-archivetype-param.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/archive-interpreter/valid-valid-archivetype-param.jv diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index 881c1b63d..3628e2ff6 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -182,6 +182,33 @@ describe('Validation of PropertyAssignment', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(0); }); + describe('ArchiveInterpreter blocktype', () => { + it('should diagnose no error on valid archiveType parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/archive-interpreter/valid-valid-archivetype-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid archiveType parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/archive-interpreter/invalid-invalid-archivetype-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "archiveType" must be one of the following values: "zip", "gz"', + expect.any(Object), + ); + }); + }); + describe('CellWriter blocktype', () => { it('should diagnose error on wrong dimension for at parameter', async () => { const text = readJvTestAsset( diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/archive-interpreter/invalid-invalid-archivetype-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/archive-interpreter/invalid-invalid-archivetype-param.jv new file mode 100644 index 000000000..e0d6edaec --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/archive-interpreter/invalid-invalid-archivetype-param.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype ArchiveInterpreter { + archiveType: 'invalid'; + } + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/archive-interpreter/valid-valid-archivetype-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/archive-interpreter/valid-valid-archivetype-param.jv new file mode 100644 index 000000000..816879c0f --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/archive-interpreter/valid-valid-archivetype-param.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype ArchiveInterpreter { + archiveType: 'zip'; + } + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} From d8a560545ebd3fcd728fea3f9ff6706ddef38edd Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 5 Sep 2023 17:53:40 +0200 Subject: [PATCH 13/43] Fix too eager validation --- libs/language-server/src/lib/ast/expressions/evaluation.ts | 3 +++ .../src/lib/validation/checks/property-assignment.ts | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/libs/language-server/src/lib/ast/expressions/evaluation.ts b/libs/language-server/src/lib/ast/expressions/evaluation.ts index 17635a29f..3dd5d8d88 100644 --- a/libs/language-server/src/lib/ast/expressions/evaluation.ts +++ b/libs/language-server/src/lib/ast/expressions/evaluation.ts @@ -184,6 +184,9 @@ export function evaluatePropertyValue( assert( result === undefined || valuetype.isInternalValueRepresentation(result), + `Evaluation result ${ + result?.toString() ?? 'undefined' + } is not valid: Neither undefined, nor of type ${valuetype.getName()}`, ); return result; } diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index 658da2631..fb7d22394 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -48,6 +48,10 @@ export function validatePropertyAssignment( evaluationContext, ); + if (validationContext.hasErrorOccurred()) { + return; + } + checkBlocktypeSpecificProperties( property, propertySpec, From 72866d573c79388920682fc2038ad7710e2bb0bb Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Wed, 6 Sep 2023 10:26:07 +0200 Subject: [PATCH 14/43] Move validations from HttpExtractor to property assignment validations --- .../checks/property-assignment.spec.ts | 77 +++++++++++++++++++ .../validation/checks/property-assignment.ts | 72 +++++++++++++++++ .../builtin-blocktypes/HttpExtractor.jv | 28 +------ .../invalid-invalid-retries-param.jv | 14 ++++ ...-invalid-retryBackoffMilliseconds-param.jv | 14 ++++ ...alid-invalid-retryBackoffStrategy-param.jv | 14 ++++ .../valid-valid-retries-param.jv | 14 ++++ ...id-valid-retryBackoffMilliseconds-param.jv | 14 ++++ .../valid-valid-retryBackoffStrategy-param.jv | 14 ++++ 9 files changed, 236 insertions(+), 25 deletions(-) create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retries-param.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffMilliseconds-param.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffStrategy-param.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retries-param.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffMilliseconds-param.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffStrategy-param.jv diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index 3628e2ff6..ca804d0db 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -279,4 +279,81 @@ describe('Validation of PropertyAssignment', () => { ); }); }); + + describe('HttpExtractor blocktype', () => { + it('should diagnose no error on valid retries parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/valid-valid-retries-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid retries parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/invalid-invalid-retries-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "retries" must not be smaller than 0', + expect.any(Object), + ); + }); + + it('should diagnose no error on valid retryBackoffMilliseconds parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffMilliseconds-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid retryBackoffMilliseconds parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffMilliseconds-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "retryBackoffMilliseconds" must not be smaller than 1000', + expect.any(Object), + ); + }); + + it('should diagnose no error on valid retryBackoffStrategy parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffStrategy-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid retryBackoffStrategy parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffStrategy-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "retryBackoffStrategy" must be one of the following values: "exponential", "linear"', + expect.any(Object), + ); + }); + }); }); diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index fb7d22394..8cdce4518 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -176,6 +176,13 @@ function checkBlocktypeSpecificProperties( property, validationContext, ); + case 'HttpExtractor': + return checkHttpExtractorProperty( + propName, + propValue, + property, + validationContext, + ); default: } } @@ -196,6 +203,7 @@ function checkArchiveInterpreterProperty( .join(', ')}`, { node: property, + property: 'value', }, ); } @@ -277,6 +285,70 @@ function checkGtfsRTInterpreterProperty( .join(', ')}`, { node: property, + property: 'value', + }, + ); + } + } +} + +function checkHttpExtractorProperty( + propName: string, + propValue: InternalValueRepresentation, + property: PropertyAssignment, + validationContext: ValidationContext, +) { + if (propName === 'retries') { + const minRetryValue = 0; + if ( + propValue !== undefined && + typeof propValue === 'number' && + propValue < minRetryValue + ) { + validationContext.accept( + 'error', + `The value of property "${propName}" must not be smaller than ${minRetryValue}`, + { + node: property, + property: 'value', + }, + ); + } + } + if (propName === 'retryBackoffMilliseconds') { + const minBackoffValue = 1000; + if ( + propValue !== undefined && + typeof propValue === 'number' && + propValue < minBackoffValue + ) { + validationContext.accept( + 'error', + `The value of property "${propName}" must not be smaller than ${minBackoffValue}`, + { + node: property, + property: 'value', + }, + ); + } + } + if (propName === 'retryBackoffStrategy') { + const allowedRetryStrategies: InternalValueRepresentation[] = [ + 'exponential', + 'linear', + ]; + if ( + propValue !== undefined && + !allowedRetryStrategies.includes(propValue) + ) { + validationContext.accept( + 'error', + `The value of property "${propName}" must be one of the following values: ${allowedRetryStrategies + .map((v) => `"${v.toString()}"`) + .join(', ')}`, + { + node: property, + property: 'value', }, ); } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv index 42ab7f3c0..35983ba28 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv @@ -13,33 +13,11 @@ builtin blocktype HttpExtractor { // The URL to the file in the web to extract. property url oftype text; // Configures how many retries should be executed after a failure fetching the data. - property retries oftype Count: 0; + property retries oftype integer: 0; // Configures the wait time in milliseconds before executing a retry. - property retryBackoffMilliseconds oftype RetryIntervalMilliseconds: 1000; + property retryBackoffMilliseconds oftype integer: 1000; // Configures the wait strategy before executing a retry. Can have values "exponential" or "linear". - property retryBackoffStrategy oftype RetryBackoffStrategy: "exponential"; + property retryBackoffStrategy oftype text: "exponential"; // Indicates, whether to follow redirects on get requests. If `false`, redirects are not followed. Default `true` property followRedirects oftype boolean: true; } - -valuetype Count oftype integer { - constraints: [IntNonNegative]; -} - -constraint IntNonNegative on integer: - value >= 0; - -valuetype RetryIntervalMilliseconds oftype integer { - constraints: [IntOver999]; -} - -constraint IntOver999 on integer: - value > 999; - -valuetype RetryBackoffStrategy oftype text { - constraints : [RetryBackoffStrategyConstraint] -} - -constraint RetryBackoffStrategyConstraint on text: - value in ["linear", "exponential"]; - diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retries-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retries-param.jv new file mode 100644 index 000000000..17d419ee2 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retries-param.jv @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype HttpExtractor { + retries: -1; // only first prop of first block is under test + url: 'http://some-url.de'; + } + block TestLoader oftype TestLoader { + } + + Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffMilliseconds-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffMilliseconds-param.jv new file mode 100644 index 000000000..727647b62 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffMilliseconds-param.jv @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype HttpExtractor { + retryBackoffMilliseconds: 999; // only first prop of first block is under test + url: 'http://some-url.de'; + } + block TestLoader oftype TestLoader { + } + + Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffStrategy-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffStrategy-param.jv new file mode 100644 index 000000000..c9a2add7d --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffStrategy-param.jv @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype HttpExtractor { + retryBackoffStrategy: 'invalid'; // only first prop of first block is under test + url: 'http://some-url.de'; + } + block TestLoader oftype TestLoader { + } + + Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retries-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retries-param.jv new file mode 100644 index 000000000..5a1b17e05 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retries-param.jv @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype HttpExtractor { + retries: 3; // only first prop of first block is under test + url: 'http://some-url.de'; + } + block TestLoader oftype TestLoader { + } + + Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffMilliseconds-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffMilliseconds-param.jv new file mode 100644 index 000000000..76fcf4f34 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffMilliseconds-param.jv @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype HttpExtractor { + retryBackoffMilliseconds: 5000; // only first prop of first block is under test + url: 'http://some-url.de'; + } + block TestLoader oftype TestLoader { + } + + Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffStrategy-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffStrategy-param.jv new file mode 100644 index 000000000..a388b10fe --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffStrategy-param.jv @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype HttpExtractor { + retryBackoffStrategy: 'linear'; // only first prop of first block is under test + url: 'http://some-url.de'; + } + block TestLoader oftype TestLoader { + } + + Test -> TestLoader; +} From 529f92820155b8a4b327f2e68a577dde9a7707e1 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Wed, 6 Sep 2023 10:32:11 +0200 Subject: [PATCH 15/43] Move validations from RowDeleter to property assignment validations --- .../checks/property-assignment.spec.ts | 27 ++++++++++++++ .../validation/checks/property-assignment.ts | 35 +++++++++++++++++++ .../stdlib/builtin-blocktypes/RowDeleter.jv | 2 +- .../row-deleter/invalid-partial-row-delete.jv | 17 +++++++++ .../row-deleter/valid-row-delete.jv | 17 +++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/row-deleter/invalid-partial-row-delete.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/row-deleter/valid-row-delete.jv diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index ca804d0db..25a3e26c1 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -356,4 +356,31 @@ describe('Validation of PropertyAssignment', () => { ); }); }); + + describe('RowDeleter blocktype', () => { + it('should diagnose error on deleting partial row', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/row-deleter/invalid-partial-row-delete.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'An entire row needs to be selected', + expect.any(Object), + ); + }); + + it('should diagnose no error', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/row-deleter/valid-row-delete.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + }); }); diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index 8cdce4518..c9b4a1dbd 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -15,6 +15,7 @@ import { evaluatePropertyValue, inferExpressionType, isColumnWrapper, + isRowWrapper, } from '../../ast'; import { PropertyAssignment, @@ -183,6 +184,13 @@ function checkBlocktypeSpecificProperties( property, validationContext, ); + case 'RowDeleter': + return checkRowDeleterProperty( + propName, + property, + validationContext, + evaluationContext, + ); default: } } @@ -354,3 +362,30 @@ function checkHttpExtractorProperty( } } } + +function checkRowDeleterProperty( + propName: string, + property: PropertyAssignment, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + if (propName === 'delete') { + const cellRanges = evaluatePropertyValue( + property, + evaluationContext, + new CollectionValuetype(PrimitiveValuetypes.CellRange), + ); + + cellRanges?.forEach((cellRange) => { + if (!isRowWrapper(cellRange)) { + validationContext.accept( + 'error', + 'An entire row needs to be selected', + { + node: cellRange.astNode, + }, + ); + } + }); + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv index e94e5a75a..16f0b7b4a 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv @@ -11,5 +11,5 @@ builtin blocktype RowDeleter { output default oftype Sheet; // The rows to delete. - property delete oftype Collection; // TODO: ensure whole row is selected + property delete oftype Collection; } \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/row-deleter/invalid-partial-row-delete.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/row-deleter/invalid-partial-row-delete.jv new file mode 100644 index 000000000..80c2e8e34 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/row-deleter/invalid-partial-row-delete.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype RowDeleter { + delete: [range A1:C1]; + } + + block TestExtractor oftype TestSheetExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/row-deleter/valid-row-delete.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/row-deleter/valid-row-delete.jv new file mode 100644 index 000000000..673fe5f6d --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/row-deleter/valid-row-delete.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype RowDeleter { + delete: [row 1]; + } + + block TestExtractor oftype TestSheetExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} From d73e1d7bbde96b54b74a8a553486c75091e7310c Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Wed, 6 Sep 2023 10:41:19 +0200 Subject: [PATCH 16/43] Move validations from TableInterpreter to property assignment validations --- .../checks/property-assignment.spec.ts | 34 +++++++++++++++++++ .../validation/checks/property-assignment.ts | 32 ++++++++++++++++- .../builtin-blocktypes/TableInterpreter.jv | 2 +- .../invalid-non-unique-column-names.jv | 20 +++++++++++ .../table-interpreter/valid-correct-table.jv | 20 +++++++++++ 5 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/table-interpreter/invalid-non-unique-column-names.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/table-interpreter/valid-correct-table.jv diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index 25a3e26c1..996f3443b 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -383,4 +383,38 @@ describe('Validation of PropertyAssignment', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(0); }); }); + + describe('TableInterpreter blocktype', () => { + it('should diagnose error on non unique column names', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/table-interpreter/invalid-non-unique-column-names.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(2); + expect(validationAcceptorMock).toHaveBeenNthCalledWith( + 1, + 'error', + 'The column name "name" needs to be unique.', + expect.any(Object), + ); + expect(validationAcceptorMock).toHaveBeenNthCalledWith( + 2, + 'error', + 'The column name "name" needs to be unique.', + expect.any(Object), + ); + }); + + it('should diagnose no error', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/table-interpreter/valid-correct-table.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + }); }); diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index c9b4a1dbd..985e820d7 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -27,7 +27,10 @@ import { PropertySpecification, } from '../../meta-information/meta-inf'; import { ValidationContext } from '../validation-context'; -import { checkExpressionSimplification } from '../validation-util'; +import { + checkExpressionSimplification, + checkUniqueNames, +} from '../validation-util'; export function validatePropertyAssignment( property: PropertyAssignment, @@ -191,6 +194,13 @@ function checkBlocktypeSpecificProperties( validationContext, evaluationContext, ); + case 'TableInterpreter': + return checkTableInterpreterProperty( + propName, + property, + validationContext, + evaluationContext, + ); default: } } @@ -389,3 +399,23 @@ function checkRowDeleterProperty( }); } } + +function checkTableInterpreterProperty( + propName: string, + property: PropertyAssignment, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + if (propName === 'columns') { + const valuetypeAssignments = evaluatePropertyValue( + property, + evaluationContext, + new CollectionValuetype(PrimitiveValuetypes.ValuetypeAssignment), + ); + if (valuetypeAssignments === undefined) { + return; + } + + checkUniqueNames(valuetypeAssignments, validationContext, 'column'); + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv index 4f79ac284..a9a028ca5 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv @@ -28,5 +28,5 @@ builtin blocktype TableInterpreter { // Whether the first row should be interpreted as header row. property header oftype boolean: true; // Collection of valuetype assignments. Uses column names (potentially matched with the header or by sequence depending on the `header` property) to assign a primitive valuetype to each column. - property columns oftype Collection; // TODO: ensure unique names + property columns oftype Collection; } \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/table-interpreter/invalid-non-unique-column-names.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/table-interpreter/invalid-non-unique-column-names.jv new file mode 100644 index 000000000..6cea9044f --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/table-interpreter/invalid-non-unique-column-names.jv @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TableInterpreter { + columns: [ + "name" oftype text, + "name" oftype integer, + ]; + } + + block TestExtractor oftype TestSheetExtractor { + } + + block TestLoader oftype TestTableLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/table-interpreter/valid-correct-table.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/table-interpreter/valid-correct-table.jv new file mode 100644 index 000000000..06cc9f9d9 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/table-interpreter/valid-correct-table.jv @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TableInterpreter { + columns: [ + "name" oftype text, + "version" oftype integer, + ]; + } + + block TestExtractor oftype TestSheetExtractor { + } + + block TestLoader oftype TestTableLoader { + } + + TestExtractor -> Test -> TestLoader; +} From e3922246b0ecfad28f4623cec901b5a16b770133 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Wed, 6 Sep 2023 11:06:59 +0200 Subject: [PATCH 17/43] Move validations from TextFileInterpreter to property assignment validations --- .../checks/property-assignment.spec.ts | 27 ++++++++++++ .../validation/checks/property-assignment.ts | 44 +++++++++++++++++++ .../builtin-blocktypes/TextFileInterpreter.jv | 11 +---- .../invalid-invalid-encoding-param.jv | 17 +++++++ .../valid-utf8-encoding-param.jv | 17 +++++++ 5 files changed, 106 insertions(+), 10 deletions(-) create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-file-interpreter/invalid-invalid-encoding-param.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-file-interpreter/valid-utf8-encoding-param.jv diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index 996f3443b..7b13eba54 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -417,4 +417,31 @@ describe('Validation of PropertyAssignment', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(0); }); }); + + describe('TextFileInterpreter blocktype', () => { + it('should diagnose no error on valid encoding parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-file-interpreter/valid-utf8-encoding-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid entity parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-file-interpreter/invalid-invalid-encoding-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "encoding" must be one of the following values: "utf8", "ibm866", "latin2", "latin3", "latin4", "cyrillic", "arabic", "greek", "hebrew", "logical", "latin6", "utf-16"', + expect.any(Object), + ); + }); + }); }); diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index 985e820d7..9875b4f50 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -201,6 +201,13 @@ function checkBlocktypeSpecificProperties( validationContext, evaluationContext, ); + case 'TextFileInterpreter': + return checkTextFileInterpreterProperty( + propName, + propValue, + property, + validationContext, + ); default: } } @@ -419,3 +426,40 @@ function checkTableInterpreterProperty( checkUniqueNames(valuetypeAssignments, validationContext, 'column'); } } + +function checkTextFileInterpreterProperty( + propName: string, + propValue: InternalValueRepresentation, + property: PropertyAssignment, + validationContext: ValidationContext, +) { + // https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API/Encodings + const allowedEncodings: InternalValueRepresentation[] = [ + 'utf8', + 'ibm866', + 'latin2', + 'latin3', + 'latin4', + 'cyrillic', + 'arabic', + 'greek', + 'hebrew', + 'logical', + 'latin6', + 'utf-16', + ]; + if (propName === 'encoding') { + if (!allowedEncodings.includes(propValue)) { + validationContext.accept( + 'error', + `The value of property "${propName}" must be one of the following values: ${allowedEncodings + .map((v) => `"${v.toString()}"`) + .join(', ')}`, + { + node: property, + property: 'value', + }, + ); + } + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv index 1f23ff278..e2c4c0d14 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv @@ -6,16 +6,7 @@ builtin blocktype TextFileInterpreter { output default oftype TextFile; // The encoding used for decoding the file contents. - property encoding oftype TextEncoding: 'utf-8'; + property encoding oftype text: 'utf-8'; // The regex for identifying line breaks. property lineBreak oftype Regex: /\r?\n/; - // TODO: check Regex valuetype } - -valuetype TextEncoding oftype text { - constraints: [TextEncodingConstraint]; -} - -constraint TextEncodingConstraint on text: - // https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API/Encodings - value in ['utf-8', 'ibm866', 'latin2', 'latin3', 'latin4', 'cyrillic', 'arabic', 'greek', 'hebrew', 'logical', 'latin6', 'utf-16']; diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-file-interpreter/invalid-invalid-encoding-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-file-interpreter/invalid-invalid-encoding-param.jv new file mode 100644 index 000000000..4a9dbe87b --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-file-interpreter/invalid-invalid-encoding-param.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TextFileInterpreter { + encoding: 'invalid'; + } + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestTextFileLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-file-interpreter/valid-utf8-encoding-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-file-interpreter/valid-utf8-encoding-param.jv new file mode 100644 index 000000000..7537150f1 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-file-interpreter/valid-utf8-encoding-param.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TextFileInterpreter { + encoding: 'utf8'; + } + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestTextFileLoader { + } + + TestExtractor -> Test -> TestLoader; +} From bd50a8ecffb268df21a8b445b33ab7cbe3d01144 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Wed, 6 Sep 2023 11:15:10 +0200 Subject: [PATCH 18/43] Move validations from TextLineDeleter to property assignment validations --- .../checks/property-assignment.spec.ts | 29 ++++++++++++++- .../validation/checks/property-assignment.ts | 36 +++++++++++++++++++ .../builtin-blocktypes/TextLineDeleter.jv | 9 +---- .../invalid-line-less-or-equal-zero.jv | 17 +++++++++ .../valid-postive-line-number.jv | 17 +++++++++ 5 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-line-deleter/invalid-line-less-or-equal-zero.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-line-deleter/valid-postive-line-number.jv diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index 7b13eba54..1180fc05b 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -429,7 +429,7 @@ describe('Validation of PropertyAssignment', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(0); }); - it('should diagnose error on invalid entity parameter value', async () => { + it('should diagnose error on invalid encoding parameter value', async () => { const text = readJvTestAsset( 'property-assignment/blocktype-specific/text-file-interpreter/invalid-invalid-encoding-param.jv', ); @@ -444,4 +444,31 @@ describe('Validation of PropertyAssignment', () => { ); }); }); + + describe('TextLineDeleter blocktype', () => { + it('should diagnose no error on valid lines parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-line-deleter/valid-postive-line-number.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid lines parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-line-deleter/invalid-line-less-or-equal-zero.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(3); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'Line numbers need to be greater than zero', + expect.any(Object), + ); + }); + }); }); diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index 9875b4f50..9f275dd2f 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -208,6 +208,13 @@ function checkBlocktypeSpecificProperties( property, validationContext, ); + case 'TextLineDeleter': + return checkTextLineDeleterProperty( + propName, + property, + validationContext, + evaluationContext, + ); default: } } @@ -463,3 +470,32 @@ function checkTextFileInterpreterProperty( } } } + +function checkTextLineDeleterProperty( + propName: string, + property: PropertyAssignment, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + if (propName === 'lines') { + const minTextLineIndex = 1; + const lines = evaluatePropertyValue( + property, + evaluationContext, + new CollectionValuetype(PrimitiveValuetypes.Integer), + ); + lines?.forEach((value, index) => { + if (value < minTextLineIndex) { + validationContext.accept( + 'error', + `Line numbers need to be greater than zero`, + { + node: property.value, + property: 'values', + index: index, + }, + ); + } + }); + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv index 0dca2ce41..bdf050cbf 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv @@ -6,12 +6,5 @@ builtin blocktype TextLineDeleter { output default oftype TextFile; // The line numbers to delete. - property lines oftype Collection; + property lines oftype Collection; } - -valuetype TextLine oftype integer { - constraints: [PositiveIntConstraint]; -} - -constraint PositiveIntConstraint on integer: - value > 0; \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-line-deleter/invalid-line-less-or-equal-zero.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-line-deleter/invalid-line-less-or-equal-zero.jv new file mode 100644 index 000000000..68f2df265 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-line-deleter/invalid-line-less-or-equal-zero.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TextLineDeleter { + lines: [2,3,0,-1,-20]; + } + + block TestExtractor oftype TestTextFileExtractor { + } + + block TestLoader oftype TestTextFileLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-line-deleter/valid-postive-line-number.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-line-deleter/valid-postive-line-number.jv new file mode 100644 index 000000000..fc7709419 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-line-deleter/valid-postive-line-number.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TextLineDeleter { + lines: [2,3]; + } + + block TestExtractor oftype TestTextFileExtractor { + } + + block TestLoader oftype TestTextFileLoader { + } + + TestExtractor -> Test -> TestLoader; +} From cc2a58d7287ee7269cce7a5a84eba26be337f678 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Wed, 6 Sep 2023 11:28:36 +0200 Subject: [PATCH 19/43] Move validations from TextRangeSelector to property assignment validations --- .../checks/property-assignment.spec.ts | 52 +++++++++++++++++++ .../validation/checks/property-assignment.ts | 32 ++++++++++++ .../builtin-blocktypes/TextRangeSelector.jv | 2 +- .../invalid-lineFrom-less-or-equal-zero.jv | 17 ++++++ .../invalid-lineTo-less-or-equal-zero.jv | 17 ++++++ .../valid-postive-lineFrom-number.jv | 17 ++++++ .../valid-postive-lineTo-number.jv | 17 ++++++ 7 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/invalid-lineFrom-less-or-equal-zero.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/invalid-lineTo-less-or-equal-zero.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/valid-postive-lineFrom-number.jv create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/valid-postive-lineTo-number.jv diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index 1180fc05b..264c3b1d0 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -471,4 +471,56 @@ describe('Validation of PropertyAssignment', () => { ); }); }); + + describe('TextRangeSelector blocktype', () => { + it('should diagnose no error on valid lineFrom parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-range-selector/valid-postive-lineFrom-number.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid lineFrom parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-range-selector/invalid-lineFrom-less-or-equal-zero.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "lineFrom" must not be smaller than 1', + expect.any(Object), + ); + }); + + it('should diagnose no error on valid lineTo parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-range-selector/valid-postive-lineTo-number.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid lineTo parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-range-selector/invalid-lineTo-less-or-equal-zero.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "lineTo" must not be smaller than 1', + expect.any(Object), + ); + }); + }); }); diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index 9f275dd2f..cf5e806f7 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -215,6 +215,13 @@ function checkBlocktypeSpecificProperties( validationContext, evaluationContext, ); + case 'TextRangeSelector': + return checkTextRangeSelectorProperty( + propName, + propValue, + property, + validationContext, + ); default: } } @@ -499,3 +506,28 @@ function checkTextLineDeleterProperty( }); } } + +function checkTextRangeSelectorProperty( + propName: string, + propValue: InternalValueRepresentation, + property: PropertyAssignment, + validationContext: ValidationContext, +) { + const minLineIndex = 1; + if (propName === 'lineFrom' || propName === 'lineTo') { + if ( + propValue !== undefined && + typeof propValue === 'number' && + propValue < minLineIndex + ) { + validationContext.accept( + 'error', + `The value of property "${propName}" must not be smaller than ${minLineIndex}`, + { + node: property, + property: 'value', + }, + ); + } + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv index f71724f28..d9c1680ef 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv @@ -6,6 +6,6 @@ builtin blocktype TextRangeSelector { output default oftype TextFile; property lineFrom oftype integer: 1; - property lineTo oftype integer: 999999; // TODO: allow sth like +Infinity + property lineTo oftype integer: 9007199254740991; // TODO: ensure lineFrom <= lineTo } \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/invalid-lineFrom-less-or-equal-zero.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/invalid-lineFrom-less-or-equal-zero.jv new file mode 100644 index 000000000..6bce31112 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/invalid-lineFrom-less-or-equal-zero.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TextRangeSelector { + lineFrom: -1; + } + + block TestExtractor oftype TestTextFileExtractor { + } + + block TestLoader oftype TestTextFileLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/invalid-lineTo-less-or-equal-zero.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/invalid-lineTo-less-or-equal-zero.jv new file mode 100644 index 000000000..8800e2c8c --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/invalid-lineTo-less-or-equal-zero.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TextRangeSelector { + lineTo: -1; + } + + block TestExtractor oftype TestTextFileExtractor { + } + + block TestLoader oftype TestTextFileLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/valid-postive-lineFrom-number.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/valid-postive-lineFrom-number.jv new file mode 100644 index 000000000..593c93164 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/valid-postive-lineFrom-number.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TextRangeSelector { + lineFrom: 2; + } + + block TestExtractor oftype TestTextFileExtractor { + } + + block TestLoader oftype TestTextFileLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/valid-postive-lineTo-number.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/valid-postive-lineTo-number.jv new file mode 100644 index 000000000..b84fac001 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/text-range-selector/valid-postive-lineTo-number.jv @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TextRangeSelector { + lineTo: 2; + } + + block TestExtractor oftype TestTextFileExtractor { + } + + block TestLoader oftype TestTextFileLoader { + } + + TestExtractor -> Test -> TestLoader; +} From 8cb933c11266d5e6fd10c4fa8ba10dc18988cae5 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Wed, 6 Sep 2023 11:39:38 +0200 Subject: [PATCH 20/43] Refactor blocktype specific property validations into own file --- .../blocktype-specific/properties.spec.ts | 433 ++++++++++++++++++ .../checks/blocktype-specific/properties.ts | 395 ++++++++++++++++ .../checks/property-assignment.spec.ts | 342 -------------- .../validation/checks/property-assignment.ts | 415 +---------------- .../invalid-invalid-retries-param.jv | 2 +- ...-invalid-retryBackoffMilliseconds-param.jv | 2 +- ...alid-invalid-retryBackoffStrategy-param.jv | 2 +- .../valid-valid-retries-param.jv | 2 +- ...id-valid-retryBackoffMilliseconds-param.jv | 2 +- .../valid-valid-retryBackoffStrategy-param.jv | 2 +- 10 files changed, 838 insertions(+), 759 deletions(-) create mode 100644 libs/language-server/src/lib/validation/checks/blocktype-specific/properties.spec.ts create mode 100644 libs/language-server/src/lib/validation/checks/blocktype-specific/properties.ts diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.spec.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.spec.ts new file mode 100644 index 000000000..0350647d7 --- /dev/null +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.spec.ts @@ -0,0 +1,433 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +import { AstNode, AstNodeLocator, LangiumDocument } from 'langium'; +import { NodeFileSystem } from 'langium/node'; + +import { + BlockMetaInformation, + EvaluationContext, + MetaInformation, + PropertyBody, + PropertySpecification, + RuntimeParameterProvider, + ValidationContext, + createJayveeServices, + getConstraintMetaInf, + isBuiltinConstrainttypeDefinition, + isReferenceableBlocktypeDefinition, +} from '../../../../lib'; +import { + ParseHelperOptions, + expectNoParserAndLexerErrors, + parseHelper, + readJvTestAssetHelper, + validationAcceptorMockImpl, +} from '../../../../test'; + +import { checkBlocktypeSpecificProperties } from './properties'; + +describe('Validation of blocktype specific properties', () => { + let parse: ( + input: string, + options?: ParseHelperOptions, + ) => Promise>; + + const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); + + let locator: AstNodeLocator; + + const readJvTestAsset = readJvTestAssetHelper( + __dirname, + '../../../../test/assets/', + ); + + async function parseAndValidatePropertyAssignment(input: string) { + const document = await parse(input); + expectNoParserAndLexerErrors(document); + + const propertyBody = locator.getAstNode( + document.parseResult.value, + 'pipelines@0/blocks@0/body', + ) as PropertyBody; + + const type = propertyBody.$container.type; + let metaInf: MetaInformation | undefined; + if (isReferenceableBlocktypeDefinition(type.ref)) { + metaInf = new BlockMetaInformation(type.ref); + } else if (isBuiltinConstrainttypeDefinition(type.ref)) { + metaInf = getConstraintMetaInf(type.ref); + } + expect(metaInf).toBeDefined(); + + propertyBody.properties.forEach((propertyAssignment) => { + const propertySpec = ( + metaInf as MetaInformation + ).getPropertySpecification(propertyAssignment.name); + expect(propertySpec).toBeDefined(); + + checkBlocktypeSpecificProperties( + propertyAssignment, + propertySpec as PropertySpecification, + new ValidationContext(validationAcceptorMock), + new EvaluationContext(new RuntimeParameterProvider()), + ); + }); + } + + beforeAll(() => { + // Create language services + const services = createJayveeServices(NodeFileSystem).Jayvee; + locator = services.workspace.AstNodeLocator; + // Parse function for Jayvee (without validation) + parse = parseHelper(services); + }); + + afterEach(() => { + // Reset mock + validationAcceptorMock.mockReset(); + }); + + describe('ArchiveInterpreter blocktype', () => { + it('should diagnose no error on valid archiveType parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/archive-interpreter/valid-valid-archivetype-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid archiveType parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/archive-interpreter/invalid-invalid-archivetype-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "archiveType" must be one of the following values: "zip", "gz"', + expect.any(Object), + ); + }); + }); + + describe('CellWriter blocktype', () => { + it('should diagnose error on wrong dimension for at parameter', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/cell-writer/invalid-wrong-at-dimension.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The cell range needs to be one-dimensional', + expect.any(Object), + ); + }); + }); + + describe('ColumnDeleter blocktype', () => { + it('should diagnose error on deleting partial column', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/column-deleter/invalid-partial-column-delete.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'An entire column needs to be selected', + expect.any(Object), + ); + }); + + it('should diagnose no error', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/column-deleter/valid-column-delete.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + }); + + describe('GtfsRTInterpreter blocktype', () => { + it('should diagnose no error on valid entity parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/gtfs-rt-interpreter/valid-valid-entity-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid entity parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/gtfs-rt-interpreter/invalid-invalid-entity-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "entity" must be one of the following values: "trip_update", "alert", "vehicle"', + expect.any(Object), + ); + }); + }); + + describe('HttpExtractor blocktype', () => { + it('should diagnose no error on valid retries parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/valid-valid-retries-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid retries parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/invalid-invalid-retries-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "retries" must not be smaller than 0', + expect.any(Object), + ); + }); + + it('should diagnose no error on valid retryBackoffMilliseconds parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffMilliseconds-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid retryBackoffMilliseconds parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffMilliseconds-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "retryBackoffMilliseconds" must not be smaller than 1000', + expect.any(Object), + ); + }); + + it('should diagnose no error on valid retryBackoffStrategy parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffStrategy-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid retryBackoffStrategy parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffStrategy-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "retryBackoffStrategy" must be one of the following values: "exponential", "linear"', + expect.any(Object), + ); + }); + }); + + describe('RowDeleter blocktype', () => { + it('should diagnose error on deleting partial row', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/row-deleter/invalid-partial-row-delete.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'An entire row needs to be selected', + expect.any(Object), + ); + }); + + it('should diagnose no error', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/row-deleter/valid-row-delete.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + }); + + describe('TableInterpreter blocktype', () => { + it('should diagnose error on non unique column names', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/table-interpreter/invalid-non-unique-column-names.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(2); + expect(validationAcceptorMock).toHaveBeenNthCalledWith( + 1, + 'error', + 'The column name "name" needs to be unique.', + expect.any(Object), + ); + expect(validationAcceptorMock).toHaveBeenNthCalledWith( + 2, + 'error', + 'The column name "name" needs to be unique.', + expect.any(Object), + ); + }); + + it('should diagnose no error', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/table-interpreter/valid-correct-table.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + }); + + describe('TextFileInterpreter blocktype', () => { + it('should diagnose no error on valid encoding parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-file-interpreter/valid-utf8-encoding-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid encoding parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-file-interpreter/invalid-invalid-encoding-param.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "encoding" must be one of the following values: "utf8", "ibm866", "latin2", "latin3", "latin4", "cyrillic", "arabic", "greek", "hebrew", "logical", "latin6", "utf-16"', + expect.any(Object), + ); + }); + }); + + describe('TextLineDeleter blocktype', () => { + it('should diagnose no error on valid lines parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-line-deleter/valid-postive-line-number.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid lines parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-line-deleter/invalid-line-less-or-equal-zero.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(3); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'Line numbers need to be greater than zero', + expect.any(Object), + ); + }); + }); + + describe('TextRangeSelector blocktype', () => { + it('should diagnose no error on valid lineFrom parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-range-selector/valid-postive-lineFrom-number.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid lineFrom parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-range-selector/invalid-lineFrom-less-or-equal-zero.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "lineFrom" must not be smaller than 1', + expect.any(Object), + ); + }); + + it('should diagnose no error on valid lineTo parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-range-selector/valid-postive-lineTo-number.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should diagnose error on invalid lineTo parameter value', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/text-range-selector/invalid-lineTo-less-or-equal-zero.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The value of property "lineTo" must not be smaller than 1', + expect.any(Object), + ); + }); + }); +}); diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.ts new file mode 100644 index 000000000..7d1943bd2 --- /dev/null +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.ts @@ -0,0 +1,395 @@ +import { + CollectionValuetype, + EvaluationContext, + InternalValueRepresentation, + PrimitiveValuetypes, + PropertyAssignment, + evaluatePropertyValue, + isColumnWrapper, + isRowWrapper, +} from '../../../ast'; +import { PropertySpecification } from '../../../meta-information'; +import { ValidationContext } from '../../validation-context'; +import { checkUniqueNames } from '../../validation-util'; + +export function checkBlocktypeSpecificProperties( + property: PropertyAssignment, + propertySpec: PropertySpecification, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + const propName = property.name; + const propValue = evaluatePropertyValue( + property, + evaluationContext, + propertySpec.type, + ); + if (propValue === undefined) { + return; + } + + switch (property.$container.$container.type.ref?.name) { + case 'ArchiveInterpreter': + return checkArchiveInterpreterProperty( + propName, + propValue, + property, + validationContext, + ); + case 'CellWriter': + return checkCellWriterProperty( + propName, + property, + validationContext, + evaluationContext, + ); + case 'ColumnDeleter': + return checkColumnDeleterProperty( + propName, + property, + validationContext, + evaluationContext, + ); + case 'GtfsRTInterpreter': + return checkGtfsRTInterpreterProperty( + propName, + propValue, + property, + validationContext, + ); + case 'HttpExtractor': + return checkHttpExtractorProperty( + propName, + propValue, + property, + validationContext, + ); + case 'RowDeleter': + return checkRowDeleterProperty( + propName, + property, + validationContext, + evaluationContext, + ); + case 'TableInterpreter': + return checkTableInterpreterProperty( + propName, + property, + validationContext, + evaluationContext, + ); + case 'TextFileInterpreter': + return checkTextFileInterpreterProperty( + propName, + propValue, + property, + validationContext, + ); + case 'TextLineDeleter': + return checkTextLineDeleterProperty( + propName, + property, + validationContext, + evaluationContext, + ); + case 'TextRangeSelector': + return checkTextRangeSelectorProperty( + propName, + propValue, + property, + validationContext, + ); + default: + } +} + +function checkArchiveInterpreterProperty( + propName: string, + propValue: InternalValueRepresentation, + property: PropertyAssignment, + validationContext: ValidationContext, +) { + const allowedArchiveTypes: InternalValueRepresentation[] = ['zip', 'gz']; + if (propName === 'archiveType') { + if (!allowedArchiveTypes.includes(propValue)) { + validationContext.accept( + 'error', + `The value of property "${propName}" must be one of the following values: ${allowedArchiveTypes + .map((v) => `"${v.toString()}"`) + .join(', ')}`, + { + node: property, + property: 'value', + }, + ); + } + } +} + +function checkCellWriterProperty( + propName: string, + property: PropertyAssignment, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + if (propName === 'at') { + const cellRange = evaluatePropertyValue( + property, + evaluationContext, + PrimitiveValuetypes.CellRange, + ); + if (cellRange === undefined) { + return; + } + + if (!cellRange.isOneDimensional()) { + validationContext.accept( + 'error', + 'The cell range needs to be one-dimensional', + { + node: cellRange.astNode, + }, + ); + } + } +} + +function checkColumnDeleterProperty( + propName: string, + property: PropertyAssignment, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + if (propName === 'delete') { + const cellRanges = evaluatePropertyValue( + property, + evaluationContext, + new CollectionValuetype(PrimitiveValuetypes.CellRange), + ); + + cellRanges?.forEach((cellRange) => { + if (!isColumnWrapper(cellRange)) { + validationContext.accept( + 'error', + 'An entire column needs to be selected', + { + node: cellRange.astNode, + }, + ); + } + }); + } +} + +function checkGtfsRTInterpreterProperty( + propName: string, + propValue: InternalValueRepresentation, + property: PropertyAssignment, + validationContext: ValidationContext, +) { + const allowedEntities: InternalValueRepresentation[] = [ + 'trip_update', + 'alert', + 'vehicle', + ]; + if (propName === 'entity') { + if (!allowedEntities.includes(propValue)) { + validationContext.accept( + 'error', + `The value of property "${propName}" must be one of the following values: ${allowedEntities + .map((v) => `"${v.toString()}"`) + .join(', ')}`, + { + node: property, + property: 'value', + }, + ); + } + } +} + +function checkHttpExtractorProperty( + propName: string, + propValue: InternalValueRepresentation, + property: PropertyAssignment, + validationContext: ValidationContext, +) { + if (propName === 'retries') { + const minRetryValue = 0; + if (typeof propValue === 'number' && propValue < minRetryValue) { + validationContext.accept( + 'error', + `The value of property "${propName}" must not be smaller than ${minRetryValue}`, + { + node: property, + property: 'value', + }, + ); + } + } + if (propName === 'retryBackoffMilliseconds') { + const minBackoffValue = 1000; + if (typeof propValue === 'number' && propValue < minBackoffValue) { + validationContext.accept( + 'error', + `The value of property "${propName}" must not be smaller than ${minBackoffValue}`, + { + node: property, + property: 'value', + }, + ); + } + } + if (propName === 'retryBackoffStrategy') { + const allowedRetryStrategies: InternalValueRepresentation[] = [ + 'exponential', + 'linear', + ]; + if (!allowedRetryStrategies.includes(propValue)) { + validationContext.accept( + 'error', + `The value of property "${propName}" must be one of the following values: ${allowedRetryStrategies + .map((v) => `"${v.toString()}"`) + .join(', ')}`, + { + node: property, + property: 'value', + }, + ); + } + } +} + +function checkRowDeleterProperty( + propName: string, + property: PropertyAssignment, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + if (propName === 'delete') { + const cellRanges = evaluatePropertyValue( + property, + evaluationContext, + new CollectionValuetype(PrimitiveValuetypes.CellRange), + ); + + cellRanges?.forEach((cellRange) => { + if (!isRowWrapper(cellRange)) { + validationContext.accept( + 'error', + 'An entire row needs to be selected', + { + node: cellRange.astNode, + }, + ); + } + }); + } +} + +function checkTableInterpreterProperty( + propName: string, + property: PropertyAssignment, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + if (propName === 'columns') { + const valuetypeAssignments = evaluatePropertyValue( + property, + evaluationContext, + new CollectionValuetype(PrimitiveValuetypes.ValuetypeAssignment), + ); + if (valuetypeAssignments === undefined) { + return; + } + + checkUniqueNames(valuetypeAssignments, validationContext, 'column'); + } +} + +function checkTextFileInterpreterProperty( + propName: string, + propValue: InternalValueRepresentation, + property: PropertyAssignment, + validationContext: ValidationContext, +) { + // https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API/Encodings + const allowedEncodings: InternalValueRepresentation[] = [ + 'utf8', + 'ibm866', + 'latin2', + 'latin3', + 'latin4', + 'cyrillic', + 'arabic', + 'greek', + 'hebrew', + 'logical', + 'latin6', + 'utf-16', + ]; + if (propName === 'encoding') { + if (!allowedEncodings.includes(propValue)) { + validationContext.accept( + 'error', + `The value of property "${propName}" must be one of the following values: ${allowedEncodings + .map((v) => `"${v.toString()}"`) + .join(', ')}`, + { + node: property, + property: 'value', + }, + ); + } + } +} + +function checkTextLineDeleterProperty( + propName: string, + property: PropertyAssignment, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + if (propName === 'lines') { + const minTextLineIndex = 1; + const lines = evaluatePropertyValue( + property, + evaluationContext, + new CollectionValuetype(PrimitiveValuetypes.Integer), + ); + lines?.forEach((value, index) => { + if (value < minTextLineIndex) { + validationContext.accept( + 'error', + `Line numbers need to be greater than zero`, + { + node: property.value, + property: 'values', + index: index, + }, + ); + } + }); + } +} + +function checkTextRangeSelectorProperty( + propName: string, + propValue: InternalValueRepresentation, + property: PropertyAssignment, + validationContext: ValidationContext, +) { + const minLineIndex = 1; + if (propName === 'lineFrom' || propName === 'lineTo') { + if (typeof propValue === 'number' && propValue < minLineIndex) { + validationContext.accept( + 'error', + `The value of property "${propName}" must not be smaller than ${minLineIndex}`, + { + node: property, + property: 'value', + }, + ); + } + } +} diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index 264c3b1d0..fe4079c55 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -181,346 +181,4 @@ describe('Validation of PropertyAssignment', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(0); }); - - describe('ArchiveInterpreter blocktype', () => { - it('should diagnose no error on valid archiveType parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/archive-interpreter/valid-valid-archivetype-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - - it('should diagnose error on invalid archiveType parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/archive-interpreter/invalid-invalid-archivetype-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(1); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'The value of property "archiveType" must be one of the following values: "zip", "gz"', - expect.any(Object), - ); - }); - }); - - describe('CellWriter blocktype', () => { - it('should diagnose error on wrong dimension for at parameter', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/cell-writer/invalid-wrong-at-dimension.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(1); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'The cell range needs to be one-dimensional', - expect.any(Object), - ); - }); - }); - - describe('ColumnDeleter blocktype', () => { - it('should diagnose error on deleting partial column', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/column-deleter/invalid-partial-column-delete.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(1); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'An entire column needs to be selected', - expect.any(Object), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/column-deleter/valid-column-delete.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - }); - - describe('GtfsRTInterpreter blocktype', () => { - it('should diagnose no error on valid entity parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/gtfs-rt-interpreter/valid-valid-entity-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - - it('should diagnose error on invalid entity parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/gtfs-rt-interpreter/invalid-invalid-entity-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(1); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'The value of property "entity" must be one of the following values: "trip_update", "alert", "vehicle"', - expect.any(Object), - ); - }); - }); - - describe('HttpExtractor blocktype', () => { - it('should diagnose no error on valid retries parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/http-extractor/valid-valid-retries-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - - it('should diagnose error on invalid retries parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/http-extractor/invalid-invalid-retries-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(1); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'The value of property "retries" must not be smaller than 0', - expect.any(Object), - ); - }); - - it('should diagnose no error on valid retryBackoffMilliseconds parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffMilliseconds-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - - it('should diagnose error on invalid retryBackoffMilliseconds parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffMilliseconds-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(1); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'The value of property "retryBackoffMilliseconds" must not be smaller than 1000', - expect.any(Object), - ); - }); - - it('should diagnose no error on valid retryBackoffStrategy parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffStrategy-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - - it('should diagnose error on invalid retryBackoffStrategy parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffStrategy-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(1); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'The value of property "retryBackoffStrategy" must be one of the following values: "exponential", "linear"', - expect.any(Object), - ); - }); - }); - - describe('RowDeleter blocktype', () => { - it('should diagnose error on deleting partial row', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/row-deleter/invalid-partial-row-delete.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(1); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'An entire row needs to be selected', - expect.any(Object), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/row-deleter/valid-row-delete.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - }); - - describe('TableInterpreter blocktype', () => { - it('should diagnose error on non unique column names', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/table-interpreter/invalid-non-unique-column-names.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(2); - expect(validationAcceptorMock).toHaveBeenNthCalledWith( - 1, - 'error', - 'The column name "name" needs to be unique.', - expect.any(Object), - ); - expect(validationAcceptorMock).toHaveBeenNthCalledWith( - 2, - 'error', - 'The column name "name" needs to be unique.', - expect.any(Object), - ); - }); - - it('should diagnose no error', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/table-interpreter/valid-correct-table.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - }); - - describe('TextFileInterpreter blocktype', () => { - it('should diagnose no error on valid encoding parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/text-file-interpreter/valid-utf8-encoding-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - - it('should diagnose error on invalid encoding parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/text-file-interpreter/invalid-invalid-encoding-param.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(1); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'The value of property "encoding" must be one of the following values: "utf8", "ibm866", "latin2", "latin3", "latin4", "cyrillic", "arabic", "greek", "hebrew", "logical", "latin6", "utf-16"', - expect.any(Object), - ); - }); - }); - - describe('TextLineDeleter blocktype', () => { - it('should diagnose no error on valid lines parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/text-line-deleter/valid-postive-line-number.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - - it('should diagnose error on invalid lines parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/text-line-deleter/invalid-line-less-or-equal-zero.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(3); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'Line numbers need to be greater than zero', - expect.any(Object), - ); - }); - }); - - describe('TextRangeSelector blocktype', () => { - it('should diagnose no error on valid lineFrom parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/text-range-selector/valid-postive-lineFrom-number.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - - it('should diagnose error on invalid lineFrom parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/text-range-selector/invalid-lineFrom-less-or-equal-zero.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(1); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'The value of property "lineFrom" must not be smaller than 1', - expect.any(Object), - ); - }); - - it('should diagnose no error on valid lineTo parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/text-range-selector/valid-postive-lineTo-number.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(0); - }); - - it('should diagnose error on invalid lineTo parameter value', async () => { - const text = readJvTestAsset( - 'property-assignment/blocktype-specific/text-range-selector/invalid-lineTo-less-or-equal-zero.jv', - ); - - await parseAndValidatePropertyAssignment(text); - - expect(validationAcceptorMock).toHaveBeenCalledTimes(1); - expect(validationAcceptorMock).toHaveBeenCalledWith( - 'error', - 'The value of property "lineTo" must not be smaller than 1', - expect.any(Object), - ); - }); - }); }); diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index cf5e806f7..dc2af1830 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -7,16 +7,7 @@ */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ -import { - CollectionValuetype, - EvaluationContext, - InternalValueRepresentation, - PrimitiveValuetypes, - evaluatePropertyValue, - inferExpressionType, - isColumnWrapper, - isRowWrapper, -} from '../../ast'; +import { EvaluationContext, inferExpressionType } from '../../ast'; import { PropertyAssignment, isBlocktypeProperty, @@ -27,10 +18,9 @@ import { PropertySpecification, } from '../../meta-information/meta-inf'; import { ValidationContext } from '../validation-context'; -import { - checkExpressionSimplification, - checkUniqueNames, -} from '../validation-util'; +import { checkExpressionSimplification } from '../validation-util'; + +import { checkBlocktypeSpecificProperties } from './blocktype-specific/properties'; export function validatePropertyAssignment( property: PropertyAssignment, @@ -134,400 +124,3 @@ function checkPropertyValueTyping( evaluationContext, ); } - -function checkBlocktypeSpecificProperties( - property: PropertyAssignment, - propertySpec: PropertySpecification, - validationContext: ValidationContext, - evaluationContext: EvaluationContext, -) { - const propName = property.name; - const propValue = evaluatePropertyValue( - property, - evaluationContext, - propertySpec.type, - ); - if (propValue === undefined) { - return; - } - - switch (property.$container.$container.type.ref?.name) { - case 'ArchiveInterpreter': - return checkArchiveInterpreterProperty( - propName, - propValue, - property, - validationContext, - ); - case 'CellWriter': - return checkCellWriterProperty( - propName, - property, - validationContext, - evaluationContext, - ); - case 'ColumnDeleter': - return checkColumnDeleterProperty( - propName, - property, - validationContext, - evaluationContext, - ); - case 'GtfsRTInterpreter': - return checkGtfsRTInterpreterProperty( - propName, - propValue, - property, - validationContext, - ); - case 'HttpExtractor': - return checkHttpExtractorProperty( - propName, - propValue, - property, - validationContext, - ); - case 'RowDeleter': - return checkRowDeleterProperty( - propName, - property, - validationContext, - evaluationContext, - ); - case 'TableInterpreter': - return checkTableInterpreterProperty( - propName, - property, - validationContext, - evaluationContext, - ); - case 'TextFileInterpreter': - return checkTextFileInterpreterProperty( - propName, - propValue, - property, - validationContext, - ); - case 'TextLineDeleter': - return checkTextLineDeleterProperty( - propName, - property, - validationContext, - evaluationContext, - ); - case 'TextRangeSelector': - return checkTextRangeSelectorProperty( - propName, - propValue, - property, - validationContext, - ); - default: - } -} - -function checkArchiveInterpreterProperty( - propName: string, - propValue: InternalValueRepresentation, - property: PropertyAssignment, - validationContext: ValidationContext, -) { - const allowedArchiveTypes: InternalValueRepresentation[] = ['zip', 'gz']; - if (propName === 'archiveType') { - if (!allowedArchiveTypes.includes(propValue)) { - validationContext.accept( - 'error', - `The value of property "${propName}" must be one of the following values: ${allowedArchiveTypes - .map((v) => `"${v.toString()}"`) - .join(', ')}`, - { - node: property, - property: 'value', - }, - ); - } - } -} - -function checkCellWriterProperty( - propName: string, - property: PropertyAssignment, - validationContext: ValidationContext, - evaluationContext: EvaluationContext, -) { - if (propName === 'at') { - const cellRange = evaluatePropertyValue( - property, - evaluationContext, - PrimitiveValuetypes.CellRange, - ); - if (cellRange === undefined) { - return; - } - - if (!cellRange.isOneDimensional()) { - validationContext.accept( - 'error', - 'The cell range needs to be one-dimensional', - { - node: cellRange.astNode, - }, - ); - } - } -} - -function checkColumnDeleterProperty( - propName: string, - property: PropertyAssignment, - validationContext: ValidationContext, - evaluationContext: EvaluationContext, -) { - if (propName === 'delete') { - const cellRanges = evaluatePropertyValue( - property, - evaluationContext, - new CollectionValuetype(PrimitiveValuetypes.CellRange), - ); - - cellRanges?.forEach((cellRange) => { - if (!isColumnWrapper(cellRange)) { - validationContext.accept( - 'error', - 'An entire column needs to be selected', - { - node: cellRange.astNode, - }, - ); - } - }); - } -} - -function checkGtfsRTInterpreterProperty( - propName: string, - propValue: InternalValueRepresentation, - property: PropertyAssignment, - validationContext: ValidationContext, -) { - const allowedEntities: InternalValueRepresentation[] = [ - 'trip_update', - 'alert', - 'vehicle', - ]; - if (propName === 'entity') { - if (!allowedEntities.includes(propValue)) { - validationContext.accept( - 'error', - `The value of property "${propName}" must be one of the following values: ${allowedEntities - .map((v) => `"${v.toString()}"`) - .join(', ')}`, - { - node: property, - property: 'value', - }, - ); - } - } -} - -function checkHttpExtractorProperty( - propName: string, - propValue: InternalValueRepresentation, - property: PropertyAssignment, - validationContext: ValidationContext, -) { - if (propName === 'retries') { - const minRetryValue = 0; - if ( - propValue !== undefined && - typeof propValue === 'number' && - propValue < minRetryValue - ) { - validationContext.accept( - 'error', - `The value of property "${propName}" must not be smaller than ${minRetryValue}`, - { - node: property, - property: 'value', - }, - ); - } - } - if (propName === 'retryBackoffMilliseconds') { - const minBackoffValue = 1000; - if ( - propValue !== undefined && - typeof propValue === 'number' && - propValue < minBackoffValue - ) { - validationContext.accept( - 'error', - `The value of property "${propName}" must not be smaller than ${minBackoffValue}`, - { - node: property, - property: 'value', - }, - ); - } - } - if (propName === 'retryBackoffStrategy') { - const allowedRetryStrategies: InternalValueRepresentation[] = [ - 'exponential', - 'linear', - ]; - if ( - propValue !== undefined && - !allowedRetryStrategies.includes(propValue) - ) { - validationContext.accept( - 'error', - `The value of property "${propName}" must be one of the following values: ${allowedRetryStrategies - .map((v) => `"${v.toString()}"`) - .join(', ')}`, - { - node: property, - property: 'value', - }, - ); - } - } -} - -function checkRowDeleterProperty( - propName: string, - property: PropertyAssignment, - validationContext: ValidationContext, - evaluationContext: EvaluationContext, -) { - if (propName === 'delete') { - const cellRanges = evaluatePropertyValue( - property, - evaluationContext, - new CollectionValuetype(PrimitiveValuetypes.CellRange), - ); - - cellRanges?.forEach((cellRange) => { - if (!isRowWrapper(cellRange)) { - validationContext.accept( - 'error', - 'An entire row needs to be selected', - { - node: cellRange.astNode, - }, - ); - } - }); - } -} - -function checkTableInterpreterProperty( - propName: string, - property: PropertyAssignment, - validationContext: ValidationContext, - evaluationContext: EvaluationContext, -) { - if (propName === 'columns') { - const valuetypeAssignments = evaluatePropertyValue( - property, - evaluationContext, - new CollectionValuetype(PrimitiveValuetypes.ValuetypeAssignment), - ); - if (valuetypeAssignments === undefined) { - return; - } - - checkUniqueNames(valuetypeAssignments, validationContext, 'column'); - } -} - -function checkTextFileInterpreterProperty( - propName: string, - propValue: InternalValueRepresentation, - property: PropertyAssignment, - validationContext: ValidationContext, -) { - // https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API/Encodings - const allowedEncodings: InternalValueRepresentation[] = [ - 'utf8', - 'ibm866', - 'latin2', - 'latin3', - 'latin4', - 'cyrillic', - 'arabic', - 'greek', - 'hebrew', - 'logical', - 'latin6', - 'utf-16', - ]; - if (propName === 'encoding') { - if (!allowedEncodings.includes(propValue)) { - validationContext.accept( - 'error', - `The value of property "${propName}" must be one of the following values: ${allowedEncodings - .map((v) => `"${v.toString()}"`) - .join(', ')}`, - { - node: property, - property: 'value', - }, - ); - } - } -} - -function checkTextLineDeleterProperty( - propName: string, - property: PropertyAssignment, - validationContext: ValidationContext, - evaluationContext: EvaluationContext, -) { - if (propName === 'lines') { - const minTextLineIndex = 1; - const lines = evaluatePropertyValue( - property, - evaluationContext, - new CollectionValuetype(PrimitiveValuetypes.Integer), - ); - lines?.forEach((value, index) => { - if (value < minTextLineIndex) { - validationContext.accept( - 'error', - `Line numbers need to be greater than zero`, - { - node: property.value, - property: 'values', - index: index, - }, - ); - } - }); - } -} - -function checkTextRangeSelectorProperty( - propName: string, - propValue: InternalValueRepresentation, - property: PropertyAssignment, - validationContext: ValidationContext, -) { - const minLineIndex = 1; - if (propName === 'lineFrom' || propName === 'lineTo') { - if ( - propValue !== undefined && - typeof propValue === 'number' && - propValue < minLineIndex - ) { - validationContext.accept( - 'error', - `The value of property "${propName}" must not be smaller than ${minLineIndex}`, - { - node: property, - property: 'value', - }, - ); - } - } -} diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retries-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retries-param.jv index 17d419ee2..50ab17c88 100644 --- a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retries-param.jv +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retries-param.jv @@ -4,7 +4,7 @@ pipeline Pipeline { block Test oftype HttpExtractor { - retries: -1; // only first prop of first block is under test + retries: -1; url: 'http://some-url.de'; } block TestLoader oftype TestLoader { diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffMilliseconds-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffMilliseconds-param.jv index 727647b62..96445ed4c 100644 --- a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffMilliseconds-param.jv +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffMilliseconds-param.jv @@ -4,7 +4,7 @@ pipeline Pipeline { block Test oftype HttpExtractor { - retryBackoffMilliseconds: 999; // only first prop of first block is under test + retryBackoffMilliseconds: 999; url: 'http://some-url.de'; } block TestLoader oftype TestLoader { diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffStrategy-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffStrategy-param.jv index c9a2add7d..072ea9a05 100644 --- a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffStrategy-param.jv +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/invalid-invalid-retryBackoffStrategy-param.jv @@ -4,7 +4,7 @@ pipeline Pipeline { block Test oftype HttpExtractor { - retryBackoffStrategy: 'invalid'; // only first prop of first block is under test + retryBackoffStrategy: 'invalid'; url: 'http://some-url.de'; } block TestLoader oftype TestLoader { diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retries-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retries-param.jv index 5a1b17e05..b9f25153b 100644 --- a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retries-param.jv +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retries-param.jv @@ -4,7 +4,7 @@ pipeline Pipeline { block Test oftype HttpExtractor { - retries: 3; // only first prop of first block is under test + retries: 3; url: 'http://some-url.de'; } block TestLoader oftype TestLoader { diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffMilliseconds-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffMilliseconds-param.jv index 76fcf4f34..7fec1dec0 100644 --- a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffMilliseconds-param.jv +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffMilliseconds-param.jv @@ -4,7 +4,7 @@ pipeline Pipeline { block Test oftype HttpExtractor { - retryBackoffMilliseconds: 5000; // only first prop of first block is under test + retryBackoffMilliseconds: 5000; url: 'http://some-url.de'; } block TestLoader oftype TestLoader { diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffStrategy-param.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffStrategy-param.jv index a388b10fe..33b56c9c2 100644 --- a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffStrategy-param.jv +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/http-extractor/valid-valid-retryBackoffStrategy-param.jv @@ -4,7 +4,7 @@ pipeline Pipeline { block Test oftype HttpExtractor { - retryBackoffStrategy: 'linear'; // only first prop of first block is under test + retryBackoffStrategy: 'linear'; url: 'http://some-url.de'; } block TestLoader oftype TestLoader { From 8536b44be568be5da943dffdaba9b388c741e2c9 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Wed, 6 Sep 2023 11:47:50 +0200 Subject: [PATCH 21/43] Pull out checkPropertyValueOneOf function --- .../checks/blocktype-specific/properties.ts | 97 ++++++++++--------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.ts index 7d1943bd2..1ad47a6f8 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.ts @@ -111,18 +111,13 @@ function checkArchiveInterpreterProperty( ) { const allowedArchiveTypes: InternalValueRepresentation[] = ['zip', 'gz']; if (propName === 'archiveType') { - if (!allowedArchiveTypes.includes(propValue)) { - validationContext.accept( - 'error', - `The value of property "${propName}" must be one of the following values: ${allowedArchiveTypes - .map((v) => `"${v.toString()}"`) - .join(', ')}`, - { - node: property, - property: 'value', - }, - ); - } + checkPropertyValueOneOf( + propValue, + allowedArchiveTypes, + propName, + property, + validationContext, + ); } } @@ -193,18 +188,13 @@ function checkGtfsRTInterpreterProperty( 'vehicle', ]; if (propName === 'entity') { - if (!allowedEntities.includes(propValue)) { - validationContext.accept( - 'error', - `The value of property "${propName}" must be one of the following values: ${allowedEntities - .map((v) => `"${v.toString()}"`) - .join(', ')}`, - { - node: property, - property: 'value', - }, - ); - } + checkPropertyValueOneOf( + propValue, + allowedEntities, + propName, + property, + validationContext, + ); } } @@ -245,18 +235,13 @@ function checkHttpExtractorProperty( 'exponential', 'linear', ]; - if (!allowedRetryStrategies.includes(propValue)) { - validationContext.accept( - 'error', - `The value of property "${propName}" must be one of the following values: ${allowedRetryStrategies - .map((v) => `"${v.toString()}"`) - .join(', ')}`, - { - node: property, - property: 'value', - }, - ); - } + checkPropertyValueOneOf( + propValue, + allowedRetryStrategies, + propName, + property, + validationContext, + ); } } @@ -329,18 +314,13 @@ function checkTextFileInterpreterProperty( 'utf-16', ]; if (propName === 'encoding') { - if (!allowedEncodings.includes(propValue)) { - validationContext.accept( - 'error', - `The value of property "${propName}" must be one of the following values: ${allowedEncodings - .map((v) => `"${v.toString()}"`) - .join(', ')}`, - { - node: property, - property: 'value', - }, - ); - } + checkPropertyValueOneOf( + propValue, + allowedEncodings, + propName, + property, + validationContext, + ); } } @@ -393,3 +373,24 @@ function checkTextRangeSelectorProperty( } } } + +function checkPropertyValueOneOf( + propValue: InternalValueRepresentation, + allowedValues: InternalValueRepresentation[], + propName: string, + property: PropertyAssignment, + validationContext: ValidationContext, +) { + if (!allowedValues.includes(propValue)) { + validationContext.accept( + 'error', + `The value of property "${propName}" must be one of the following values: ${allowedValues + .map((v) => `"${v.toString()}"`) + .join(', ')}`, + { + node: property, + property: 'value', + }, + ); + } +} From 2a5d826b0b51441a1edb956f257a2570c99efdcc Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 09:14:58 +0200 Subject: [PATCH 22/43] Move body validations from TextRangeSelector to property body validations --- .../blocktype-specific/property-body.spec.ts | 109 ++++++++++++++++++ .../blocktype-specific/property-body.ts | 64 ++++++++++ .../lib/validation/checks/property-body.ts | 10 ++ .../builtin-blocktypes/TextRangeSelector.jv | 1 - .../invalid-lineFrom-greater-lineTo.jv | 18 +++ .../valid-correct-range.jv | 18 +++ 6 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts create mode 100644 libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts create mode 100644 libs/language-server/src/test/assets/property-body/blocktype-specific/text-range-selector/invalid-lineFrom-greater-lineTo.jv create mode 100644 libs/language-server/src/test/assets/property-body/blocktype-specific/text-range-selector/valid-correct-range.jv diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts new file mode 100644 index 000000000..2d7a334f5 --- /dev/null +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts @@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +import { AstNode, AstNodeLocator, LangiumDocument } from 'langium'; +import { NodeFileSystem } from 'langium/node'; + +import { + BlockMetaInformation, + EvaluationContext, + MetaInformation, + PropertyBody, + RuntimeParameterProvider, + ValidationContext, + createJayveeServices, + getConstraintMetaInf, + isBuiltinConstrainttypeDefinition, + isReferenceableBlocktypeDefinition, +} from '../../..'; +import { + ParseHelperOptions, + expectNoParserAndLexerErrors, + parseHelper, + readJvTestAssetHelper, + validationAcceptorMockImpl, +} from '../../../../test'; + +import { checkBlocktypeSpecificPropertyBody } from './property-body'; + +describe('Validation of blocktype specific property bodies', () => { + let parse: ( + input: string, + options?: ParseHelperOptions, + ) => Promise>; + + const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); + + let locator: AstNodeLocator; + + const readJvTestAsset = readJvTestAssetHelper( + __dirname, + '../../../../test/assets/', + ); + + async function parseAndValidatePropertyAssignment(input: string) { + const document = await parse(input); + expectNoParserAndLexerErrors(document); + + const propertyBody = locator.getAstNode( + document.parseResult.value, + 'pipelines@0/blocks@0/body', + ) as PropertyBody; + + const type = propertyBody.$container.type; + let metaInf: MetaInformation | undefined; + if (isReferenceableBlocktypeDefinition(type.ref)) { + metaInf = new BlockMetaInformation(type.ref); + } else if (isBuiltinConstrainttypeDefinition(type.ref)) { + metaInf = getConstraintMetaInf(type.ref); + } + expect(metaInf).toBeDefined(); + + checkBlocktypeSpecificPropertyBody( + propertyBody, + new ValidationContext(validationAcceptorMock), + new EvaluationContext(new RuntimeParameterProvider()), + ); + } + + beforeAll(() => { + // Create language services + const services = createJayveeServices(NodeFileSystem).Jayvee; + locator = services.workspace.AstNodeLocator; + // Parse function for Jayvee (without validation) + parse = parseHelper(services); + }); + + afterEach(() => { + // Reset mock + validationAcceptorMock.mockReset(); + }); + + describe('TextRangeSelector blocktype', () => { + it('should diagnose error on lineFrom > lineTo', async () => { + const text = readJvTestAsset( + 'property-body/blocktype-specific/text-range-selector/invalid-lineFrom-greater-lineTo.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(2); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'The lower line number needs to be smaller or equal to the upper line number', + expect.any(Object), + ); + }); + + it('should diagnose no error', async () => { + const text = readJvTestAsset( + 'property-body/blocktype-specific/text-range-selector/valid-correct-range.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + }); +}); diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts new file mode 100644 index 000000000..ddfe80f04 --- /dev/null +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts @@ -0,0 +1,64 @@ +import { + EvaluationContext, + PrimitiveValuetypes, + PropertyBody, + evaluatePropertyValue, +} from '../../../ast'; +import { ValidationContext } from '../../validation-context'; + +export function checkBlocktypeSpecificPropertyBody( + propertyBody: PropertyBody, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + switch (propertyBody.$container.type.ref?.name) { + case 'TextRangeSelector': + return checkTextRangeSelectorPropertyBody( + propertyBody, + validationContext, + evaluationContext, + ); + default: + } +} + +function checkTextRangeSelectorPropertyBody( + propertyBody: PropertyBody, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + const lineFromProperty = propertyBody.properties.find( + (p) => p.name === 'lineFrom', + ); + const lineToProperty = propertyBody.properties.find( + (p) => p.name === 'lineTo', + ); + + if (lineFromProperty === undefined || lineToProperty === undefined) { + return; + } + + const lineFrom = evaluatePropertyValue( + lineFromProperty, + evaluationContext, + PrimitiveValuetypes.Integer, + ); + const lineTo = evaluatePropertyValue( + lineToProperty, + evaluationContext, + PrimitiveValuetypes.Integer, + ); + if (lineFrom === undefined || lineTo === undefined) { + return; + } + + if (lineFrom > lineTo) { + [lineFromProperty, lineToProperty].forEach((property) => { + validationContext.accept( + 'error', + 'The lower line number needs to be smaller or equal to the upper line number', + { node: property.value }, + ); + }); + } +} diff --git a/libs/language-server/src/lib/validation/checks/property-body.ts b/libs/language-server/src/lib/validation/checks/property-body.ts index f2829057b..14228a616 100644 --- a/libs/language-server/src/lib/validation/checks/property-body.ts +++ b/libs/language-server/src/lib/validation/checks/property-body.ts @@ -13,6 +13,7 @@ import { EvaluationContext } from '../../ast/expressions/evaluation'; import { PropertyAssignment, PropertyBody, + isBlockDefinition, isBuiltinConstrainttypeDefinition, isReferenceableBlocktypeDefinition, } from '../../ast/generated/ast'; @@ -22,6 +23,7 @@ import { getConstraintMetaInf } from '../../meta-information/meta-inf-registry'; import { ValidationContext } from '../validation-context'; import { checkUniqueNames } from '../validation-util'; +import { checkBlocktypeSpecificPropertyBody } from './blocktype-specific/property-body'; import { validatePropertyAssignment } from './property-assignment'; export function validatePropertyBody( @@ -114,4 +116,12 @@ function checkCustomPropertyValidation( evaluationContext: EvaluationContext, ): void { metaInf.validate(propertyBody, validationContext, evaluationContext); + + if (isBlockDefinition(propertyBody.$container)) { + checkBlocktypeSpecificPropertyBody( + propertyBody, + validationContext, + evaluationContext, + ); + } } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv index d9c1680ef..60291d72e 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv @@ -7,5 +7,4 @@ builtin blocktype TextRangeSelector { property lineFrom oftype integer: 1; property lineTo oftype integer: 9007199254740991; - // TODO: ensure lineFrom <= lineTo } \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-body/blocktype-specific/text-range-selector/invalid-lineFrom-greater-lineTo.jv b/libs/language-server/src/test/assets/property-body/blocktype-specific/text-range-selector/invalid-lineFrom-greater-lineTo.jv new file mode 100644 index 000000000..cdd0a588c --- /dev/null +++ b/libs/language-server/src/test/assets/property-body/blocktype-specific/text-range-selector/invalid-lineFrom-greater-lineTo.jv @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TextRangeSelector { + lineFrom: 10; + lineTo: 1; + } + + block TestExtractor oftype TestTextFileExtractor { + } + + block TestLoader oftype TestTextFileLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-body/blocktype-specific/text-range-selector/valid-correct-range.jv b/libs/language-server/src/test/assets/property-body/blocktype-specific/text-range-selector/valid-correct-range.jv new file mode 100644 index 000000000..3359596c0 --- /dev/null +++ b/libs/language-server/src/test/assets/property-body/blocktype-specific/text-range-selector/valid-correct-range.jv @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype TextRangeSelector { + lineFrom: 1; + lineTo: 2; + } + + block TestExtractor oftype TestTextFileExtractor { + } + + block TestLoader oftype TestTextFileLoader { + } + + TestExtractor -> Test -> TestLoader; +} From f087692b9afecbdb40d7dc528572f1af6aef44e5 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 09:24:36 +0200 Subject: [PATCH 23/43] Move body validations from CellWriter to property body validations --- .../blocktype-specific/properties.spec.ts | 10 ++++ .../blocktype-specific/property-body.spec.ts | 34 +++++++++++++ .../blocktype-specific/property-body.ts | 49 +++++++++++++++++++ .../stdlib/builtin-blocktypes/CellWriter.jv | 1 - .../valid-one-dimensional-at-value.jv | 18 +++++++ ...-write-length-does-not-match-cell-range.jv | 18 +++++++ .../valid-range-matches-array-length.jv | 18 +++++++ 7 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 libs/language-server/src/test/assets/property-assignment/blocktype-specific/cell-writer/valid-one-dimensional-at-value.jv create mode 100644 libs/language-server/src/test/assets/property-body/blocktype-specific/cell-writer/invalid-write-length-does-not-match-cell-range.jv create mode 100644 libs/language-server/src/test/assets/property-body/blocktype-specific/cell-writer/valid-range-matches-array-length.jv diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.spec.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.spec.ts index 0350647d7..168021d21 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.spec.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.spec.ts @@ -131,6 +131,16 @@ describe('Validation of blocktype specific properties', () => { expect.any(Object), ); }); + + it('should diagnose no error on correct dimension for at parameter', async () => { + const text = readJvTestAsset( + 'property-assignment/blocktype-specific/cell-writer/valid-one-dimensional-at-value.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); }); describe('ColumnDeleter blocktype', () => { diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts index 2d7a334f5..53a6e4e4a 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts @@ -106,4 +106,38 @@ describe('Validation of blocktype specific property bodies', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(0); }); }); + + describe('CellWriter blocktype', () => { + it('should diagnose error on number of write values does not match cell range', async () => { + const text = readJvTestAsset( + 'property-body/blocktype-specific/cell-writer/invalid-write-length-does-not-match-cell-range.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(2); + expect(validationAcceptorMock).toHaveBeenNthCalledWith( + 1, + 'warning', + 'The number of values to write (3) does not match the number of cells (4)', + expect.any(Object), + ); + expect(validationAcceptorMock).toHaveBeenNthCalledWith( + 2, + 'warning', + 'The number of values to write (3) does not match the number of cells (4)', + expect.any(Object), + ); + }); + + it('should diagnose no error', async () => { + const text = readJvTestAsset( + 'property-body/blocktype-specific/cell-writer/valid-range-matches-array-length.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + }); }); diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts index ddfe80f04..6ad7f0721 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts @@ -1,4 +1,5 @@ import { + CollectionValuetype, EvaluationContext, PrimitiveValuetypes, PropertyBody, @@ -18,6 +19,12 @@ export function checkBlocktypeSpecificPropertyBody( validationContext, evaluationContext, ); + case 'CellWriter': + return checkCellWriterPropertyBody( + propertyBody, + validationContext, + evaluationContext, + ); default: } } @@ -62,3 +69,45 @@ function checkTextRangeSelectorPropertyBody( }); } } + +function checkCellWriterPropertyBody( + propertyBody: PropertyBody, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + const writeProperty = propertyBody.properties.find((p) => p.name === 'write'); + const atProperty = propertyBody.properties.find((p) => p.name === 'at'); + + if (writeProperty === undefined || atProperty === undefined) { + return; + } + + const writeValues = evaluatePropertyValue( + writeProperty, + evaluationContext, + new CollectionValuetype(PrimitiveValuetypes.Text), + ); + + const atValue = evaluatePropertyValue( + atProperty, + evaluationContext, + PrimitiveValuetypes.CellRange, + ); + + if (writeValues === undefined || atValue === undefined) { + return; + } + + const numberOfValuesToWrite = writeValues.length; + const numberOfCells = atValue.numberOfCells(); + + if (numberOfCells !== numberOfValuesToWrite) { + [writeProperty, atProperty].forEach((propertyNode) => { + validationContext.accept( + 'warning', + `The number of values to write (${numberOfValuesToWrite}) does not match the number of cells (${numberOfCells})`, + { node: propertyNode.value }, + ); + }); + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv index fc7d41a0d..87be6bd30 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv @@ -21,5 +21,4 @@ builtin blocktype CellWriter { property write oftype Collection; // The cells to write into. property at oftype CellRange; - // TODO: ensure write.length === at.values.length } \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-assignment/blocktype-specific/cell-writer/valid-one-dimensional-at-value.jv b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/cell-writer/valid-one-dimensional-at-value.jv new file mode 100644 index 000000000..f07269c42 --- /dev/null +++ b/libs/language-server/src/test/assets/property-assignment/blocktype-specific/cell-writer/valid-one-dimensional-at-value.jv @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype CellWriter { + at: range A1:A2; + write: ['the', 'values']; + } + + block TestExtractor oftype TestSheetExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-body/blocktype-specific/cell-writer/invalid-write-length-does-not-match-cell-range.jv b/libs/language-server/src/test/assets/property-body/blocktype-specific/cell-writer/invalid-write-length-does-not-match-cell-range.jv new file mode 100644 index 000000000..9384c99aa --- /dev/null +++ b/libs/language-server/src/test/assets/property-body/blocktype-specific/cell-writer/invalid-write-length-does-not-match-cell-range.jv @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype CellWriter { + at: range A1:A4; + write: ['values', 'to', 'write']; + } + + block TestExtractor oftype TestSheetExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-body/blocktype-specific/cell-writer/valid-range-matches-array-length.jv b/libs/language-server/src/test/assets/property-body/blocktype-specific/cell-writer/valid-range-matches-array-length.jv new file mode 100644 index 000000000..2d9a51d5f --- /dev/null +++ b/libs/language-server/src/test/assets/property-body/blocktype-specific/cell-writer/valid-range-matches-array-length.jv @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + block Test oftype CellWriter { + at: range A1:A3; + write: ['values', 'to', 'write']; + } + + block TestExtractor oftype TestSheetExtractor { + } + + block TestLoader oftype TestSheetLoader { + } + + TestExtractor -> Test -> TestLoader; +} From a3861f9c9078fc45c88fb4e971a11be111432e4a Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 09:31:29 +0200 Subject: [PATCH 24/43] Move body validations from TableTransformer to property body validations --- .../blocktype-specific/property-body.spec.ts | 27 ++++++++ .../blocktype-specific/property-body.ts | 69 +++++++++++++++++++ .../builtin-blocktypes/TableTransformer.jv | 1 - ...-input-columns-transform-port-missmatch.jv | 26 +++++++ .../table-transformer/valid-correct-ports.jv | 26 +++++++ 5 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 libs/language-server/src/test/assets/property-body/blocktype-specific/table-transformer/invalid-input-columns-transform-port-missmatch.jv create mode 100644 libs/language-server/src/test/assets/property-body/blocktype-specific/table-transformer/valid-correct-ports.jv diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts index 53a6e4e4a..0078b24a8 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts @@ -140,4 +140,31 @@ describe('Validation of blocktype specific property bodies', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(0); }); }); + + describe('TableTransformer blocktype', () => { + it('should diagnose error on number of input columns do not match transform input ports', async () => { + const text = readJvTestAsset( + 'property-body/blocktype-specific/table-transformer/invalid-input-columns-transform-port-missmatch.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + 'Expected 1 columns but only got 2', + expect.any(Object), + ); + }); + + it('should diagnose no error', async () => { + const text = readJvTestAsset( + 'property-body/blocktype-specific/table-transformer/valid-correct-ports.jv', + ); + + await parseAndValidatePropertyAssignment(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + }); }); diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts index 6ad7f0721..bff57b615 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts @@ -25,6 +25,12 @@ export function checkBlocktypeSpecificPropertyBody( validationContext, evaluationContext, ); + case 'TableTransformer': + return checkTableTransformerPropertyBody( + propertyBody, + validationContext, + evaluationContext, + ); default: } } @@ -111,3 +117,66 @@ function checkCellWriterPropertyBody( }); } } + +function checkTableTransformerPropertyBody( + propertyBody: PropertyBody, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +) { + checkInputColumnsMatchTransformationPorts( + propertyBody, + validationContext, + evaluationContext, + ); +} + +function checkInputColumnsMatchTransformationPorts( + propertyBody: PropertyBody, + validationContext: ValidationContext, + evaluationContext: EvaluationContext, +): void { + const useProperty = propertyBody.properties.find((x) => x.name === 'use'); + const inputColumnsProperty = propertyBody.properties.find( + (x) => x.name === 'inputColumns', + ); + + if (useProperty === undefined || inputColumnsProperty === undefined) { + return; + } + + const transform = evaluatePropertyValue( + useProperty, + evaluationContext, + PrimitiveValuetypes.Transform, + ); + const inputColumns = evaluatePropertyValue( + inputColumnsProperty, + evaluationContext, + new CollectionValuetype(PrimitiveValuetypes.Text), + ); + + if (transform === undefined || inputColumns === undefined) { + return; + } + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + const transformInputPorts = transform?.body?.ports?.filter( + (x) => x.kind === 'from', + ); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (transformInputPorts === undefined) { + return; + } + + const numberTransformPorts = transformInputPorts.length; + const numberInputColumns = inputColumns.length; + + if (numberTransformPorts !== numberInputColumns) { + validationContext.accept( + 'error', + `Expected ${numberTransformPorts} columns but only got ${numberInputColumns}`, + { + node: inputColumnsProperty, + }, + ); + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv index 1676c7c59..0afc735a9 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv @@ -41,5 +41,4 @@ builtin blocktype TableTransformer { property outputColumn oftype text; // Reference to the transform that is applied to the column. property use oftype Transform; - // TODO: checkInputColumnsMatchTransformationPorts } \ No newline at end of file diff --git a/libs/language-server/src/test/assets/property-body/blocktype-specific/table-transformer/invalid-input-columns-transform-port-missmatch.jv b/libs/language-server/src/test/assets/property-body/blocktype-specific/table-transformer/invalid-input-columns-transform-port-missmatch.jv new file mode 100644 index 000000000..4179d0a04 --- /dev/null +++ b/libs/language-server/src/test/assets/property-body/blocktype-specific/table-transformer/invalid-input-columns-transform-port-missmatch.jv @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + transform TestTransform { + from inputParam oftype decimal; + to result oftype integer; + + result: ceil(inputParam); + } + + block Test oftype TableTransformer { + inputColumns: ['input1', 'input2']; + outputColumn: 'output'; + use: TestTransform; + } + + block TestExtractor oftype TestTableExtractor { + } + + block TestLoader oftype TestTableLoader { + } + + TestExtractor -> Test -> TestLoader; +} diff --git a/libs/language-server/src/test/assets/property-body/blocktype-specific/table-transformer/valid-correct-ports.jv b/libs/language-server/src/test/assets/property-body/blocktype-specific/table-transformer/valid-correct-ports.jv new file mode 100644 index 000000000..c6da883da --- /dev/null +++ b/libs/language-server/src/test/assets/property-body/blocktype-specific/table-transformer/valid-correct-ports.jv @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline Pipeline { + transform TestTransform { + from inputParam oftype decimal; + to result oftype integer; + + result: ceil(inputParam); + } + + block Test oftype TableTransformer { + inputColumns: ['input1']; + outputColumn: 'output'; + use: TestTransform; + } + + block TestExtractor oftype TestTableExtractor { + } + + block TestLoader oftype TestTableLoader { + } + + TestExtractor -> Test -> TestLoader; +} From d249c7e23263f9434a943fd9ec3d51d666050a30 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 09:32:52 +0200 Subject: [PATCH 25/43] Move body validations from TableTransformer to property body validations --- .../{properties.spec.ts => property-assignment.spec.ts} | 4 ++-- .../{properties.ts => property-assignment.ts} | 0 .../src/lib/validation/checks/property-assignment.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename libs/language-server/src/lib/validation/checks/blocktype-specific/{properties.spec.ts => property-assignment.spec.ts} (99%) rename libs/language-server/src/lib/validation/checks/blocktype-specific/{properties.ts => property-assignment.ts} (100%) diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.spec.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.spec.ts similarity index 99% rename from libs/language-server/src/lib/validation/checks/blocktype-specific/properties.spec.ts rename to libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.spec.ts index 168021d21..0c1dd2098 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.spec.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.spec.ts @@ -17,7 +17,7 @@ import { getConstraintMetaInf, isBuiltinConstrainttypeDefinition, isReferenceableBlocktypeDefinition, -} from '../../../../lib'; +} from '../../..'; import { ParseHelperOptions, expectNoParserAndLexerErrors, @@ -26,7 +26,7 @@ import { validationAcceptorMockImpl, } from '../../../../test'; -import { checkBlocktypeSpecificProperties } from './properties'; +import { checkBlocktypeSpecificProperties } from './property-assignment'; describe('Validation of blocktype specific properties', () => { let parse: ( diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/properties.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.ts similarity index 100% rename from libs/language-server/src/lib/validation/checks/blocktype-specific/properties.ts rename to libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.ts diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.ts b/libs/language-server/src/lib/validation/checks/property-assignment.ts index dc2af1830..b4672e680 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -20,7 +20,7 @@ import { import { ValidationContext } from '../validation-context'; import { checkExpressionSimplification } from '../validation-util'; -import { checkBlocktypeSpecificProperties } from './blocktype-specific/properties'; +import { checkBlocktypeSpecificProperties } from './blocktype-specific/property-assignment'; export function validatePropertyAssignment( property: PropertyAssignment, From 6337d406c92c3f61b883c493295ddc6327f23a9e Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 09:37:32 +0200 Subject: [PATCH 26/43] Resolve TODO in runtime parameter literal validation --- .../src/validation-checks/runtime-parameter-literal.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts index 45351bcbe..2fba3ddc4 100644 --- a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts +++ b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts @@ -80,10 +80,10 @@ function checkRuntimeParameterValueParsing( } let metaInf: MetaInformation | undefined; - if (isReferenceableBlocktypeDefinition(type.ref)) { - if (!BlockMetaInformation.canBeWrapped(type.ref)) { - return; // TODO: is this the rigth thing to do here? - } + if ( + isReferenceableBlocktypeDefinition(type.ref) && + BlockMetaInformation.canBeWrapped(type.ref) + ) { metaInf = new BlockMetaInformation(type.ref); } else if (isBuiltinConstrainttypeDefinition(type.ref)) { metaInf = getConstraintMetaInf(type.ref); From 7fec95313f2502834a5c1ce8b489f88be6a39f9f Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 09:38:58 +0200 Subject: [PATCH 27/43] Remove TODO in BlockMetaInformation --- libs/language-server/src/lib/meta-information/block-meta-inf.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/language-server/src/lib/meta-information/block-meta-inf.ts b/libs/language-server/src/lib/meta-information/block-meta-inf.ts index ce5730122..ad65a7f08 100644 --- a/libs/language-server/src/lib/meta-information/block-meta-inf.ts +++ b/libs/language-server/src/lib/meta-information/block-meta-inf.ts @@ -56,7 +56,7 @@ export class BlockMetaInformation extends MetaInformation { const defaultValue = evaluateExpression( property.defaultValue, - new EvaluationContext(new RuntimeParameterProvider()), // TODO: check if that works + new EvaluationContext(new RuntimeParameterProvider()), ); if (defaultValue !== undefined) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion From f81202898d2d39c84b9d7ee26e74ce04eee46d45 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 16:56:12 +0200 Subject: [PATCH 28/43] Iterate over all registered blocktypes where necessary with new way --- apps/docs/generator/src/main.ts | 40 +++++++++--- .../interpreter-lib/src/std-extension.spec.ts | 63 ++++++++++++++----- 2 files changed, 82 insertions(+), 21 deletions(-) diff --git a/apps/docs/generator/src/main.ts b/apps/docs/generator/src/main.ts index de7cdaa41..bbaad1aea 100644 --- a/apps/docs/generator/src/main.ts +++ b/apps/docs/generator/src/main.ts @@ -8,21 +8,46 @@ import { join } from 'path'; import { BlockMetaInformation, PrimitiveValuetypes, + createJayveeServices, getRegisteredConstraintMetaInformation, - registerConstraints, + initializeWorkspace, + isJayveeModel, } from '@jvalue/jayvee-language-server'; +import { LangiumDocuments } from 'langium'; +import { NodeFileSystem } from 'langium/node'; import { UserDocGenerator } from './user-doc-generator'; -function main(): void { +async function main(): Promise { const rootPath = join(__dirname, '..', '..', '..', '..'); - generateBlockTypeDocs(rootPath); + + const services = createJayveeServices(NodeFileSystem).Jayvee; + await initializeWorkspace(services); + const documentService = services.shared.workspace.LangiumDocuments; + + generateBlockTypeDocs(documentService, rootPath); generateConstraintTypeDocs(rootPath); generateValueTypeDocs(rootPath); generateExampleDocs(rootPath); } -function generateBlockTypeDocs(rootPath: string): void { +function generateBlockTypeDocs( + documentService: LangiumDocuments, + rootPath: string, +): void { + const metaInfs: BlockMetaInformation[] = []; + documentService.all + .map((document) => document.parseResult.value) + .forEach((parsedDocument) => { + if (!isJayveeModel(parsedDocument)) { + throw new Error('Expected parsed document to be a JayveeModel'); + } + parsedDocument.blocktypes.forEach((blocktypeDefinition) => { + if (BlockMetaInformation.canBeWrapped(blocktypeDefinition)) { + metaInfs.push(new BlockMetaInformation(blocktypeDefinition)); + } + }); + }); const docsPath = join( rootPath, 'apps', @@ -31,7 +56,7 @@ function generateBlockTypeDocs(rootPath: string): void { 'user', 'block-types', ); - const metaInfs: BlockMetaInformation[] = []; // TODO: load from Std Lib + for (const metaInf of metaInfs) { const userDocBuilder = new UserDocGenerator(); const blockTypeDoc = userDocBuilder.generateBlockTypeDoc(metaInf); @@ -53,7 +78,6 @@ function generateConstraintTypeDocs(rootPath: string): void { 'user', 'constraint-types', ); - registerConstraints(); const metaInfs = getRegisteredConstraintMetaInformation(); for (const metaInf of metaInfs) { @@ -109,4 +133,6 @@ ${exampleModel.toString()} } } -main(); +main() + .then(() => console.log('Finished generating docs!')) + .catch((e) => console.error(e)); diff --git a/libs/interpreter-lib/src/std-extension.spec.ts b/libs/interpreter-lib/src/std-extension.spec.ts index 958679fd0..2fe2046dc 100644 --- a/libs/interpreter-lib/src/std-extension.spec.ts +++ b/libs/interpreter-lib/src/std-extension.spec.ts @@ -5,26 +5,61 @@ import { strict as assert } from 'assert'; import { getRegisteredBlockExecutors } from '@jvalue/jayvee-execution'; -import { BlockMetaInformation } from '@jvalue/jayvee-language-server'; +import { + BlockMetaInformation, + createJayveeServices, + initializeWorkspace, + isBuiltinBlocktypeDefinition, + isJayveeModel, +} from '@jvalue/jayvee-language-server'; +import { NodeFileSystem } from 'langium/node'; import { useStdExtension } from './interpreter'; +async function getAllBuiltinBlocktypes(): Promise { + const allBuiltinBlocktypes: BlockMetaInformation[] = []; + const services = createJayveeServices(NodeFileSystem).Jayvee; + await initializeWorkspace(services); + const documentService = services.shared.workspace.LangiumDocuments; + + documentService.all + .map((document) => document.parseResult.value) + .forEach((parsedDocument) => { + if (!isJayveeModel(parsedDocument)) { + throw new Error('Expected parsed document to be a JayveeModel'); + } + parsedDocument.blocktypes.forEach((blocktypeDefinition) => { + if (!isBuiltinBlocktypeDefinition(blocktypeDefinition)) { + return; + } + if (BlockMetaInformation.canBeWrapped(blocktypeDefinition)) { + allBuiltinBlocktypes.push( + new BlockMetaInformation(blocktypeDefinition), + ); + } + }); + }); + return allBuiltinBlocktypes; +} + describe('std extension', () => { - useStdExtension(); - [].forEach((metaInf: BlockMetaInformation) => { - // TODO: iterate over all block meta inf - it(`should provide a matching block executor for block type ${metaInf.type}`, () => { - const matchingBlockExecutorClass = getRegisteredBlockExecutors().find( - (blockExecutorClass) => blockExecutorClass.type === metaInf.type, - ); + it('should provide matching block executors for builtin block types', async () => { + useStdExtension(); + (await getAllBuiltinBlocktypes()).forEach( + (metaInf: BlockMetaInformation) => { + console.info(`Looking for executor for blocktype ${metaInf.type}`); + const matchingBlockExecutorClass = getRegisteredBlockExecutors().find( + (blockExecutorClass) => blockExecutorClass.type === metaInf.type, + ); - expect(matchingBlockExecutorClass).toBeDefined(); - assert(matchingBlockExecutorClass !== undefined); + expect(matchingBlockExecutorClass).toBeDefined(); + assert(matchingBlockExecutorClass !== undefined); - const matchingBlockExecutor = new matchingBlockExecutorClass(); + const matchingBlockExecutor = new matchingBlockExecutorClass(); - expect(matchingBlockExecutor.inputType).toEqual(metaInf.inputType); - expect(matchingBlockExecutor.outputType).toEqual(metaInf.outputType); - }); + expect(matchingBlockExecutor.inputType).toEqual(metaInf.inputType); + expect(matchingBlockExecutor.outputType).toEqual(metaInf.outputType); + }, + ); }); }); From 80d0a0bfc0df244037e38b9472e7dc83f0bb605f Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 17:01:16 +0200 Subject: [PATCH 29/43] Implement BlockMetaInformation.canBeWrapped --- .../lib/meta-information/block-meta-inf.ts | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/libs/language-server/src/lib/meta-information/block-meta-inf.ts b/libs/language-server/src/lib/meta-information/block-meta-inf.ts index ad65a7f08..e2bf5f8ae 100644 --- a/libs/language-server/src/lib/meta-information/block-meta-inf.ts +++ b/libs/language-server/src/lib/meta-information/block-meta-inf.ts @@ -88,10 +88,26 @@ export class BlockMetaInformation extends MetaInformation { return false; } - // TODO: implement - if (isBuiltinBlocktypeDefinition(blocktypeDefinition)) { - return true; + if ( + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + blocktypeDefinition.properties === undefined || + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + blocktypeDefinition.name === undefined || + blocktypeDefinition.inputs[0] === undefined || + blocktypeDefinition.outputs[0] === undefined + ) { + return false; } + + if ( + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + blocktypeDefinition.properties.some((property) => { + property.valueType.reference.ref === undefined; + }) + ) { + return false; + } + return true; } From 718316c8ed688fb233dbc7bcf10d2d14d1ad4fef Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 17:34:51 +0200 Subject: [PATCH 30/43] Generate documentation of blocktype and examples from blocktype definition --- apps/docs/generator/src/main.ts | 30 +++--- apps/docs/generator/src/user-doc-generator.ts | 23 ++++- libs/language-server/src/lib/jayvee-module.ts | 5 + .../lib/meta-information/block-meta-inf.ts | 11 +-- .../services/jayvee-documentation-provider.ts | 15 +++ .../builtin-blocktypes/CsvInterpreter.jv | 4 +- .../builtin-blocktypes/GtfsRtInterpreter.jv | 95 +++++++++---------- 7 files changed, 114 insertions(+), 69 deletions(-) create mode 100644 libs/language-server/src/lib/services/jayvee-documentation-provider.ts diff --git a/apps/docs/generator/src/main.ts b/apps/docs/generator/src/main.ts index bbaad1aea..69b614e31 100644 --- a/apps/docs/generator/src/main.ts +++ b/apps/docs/generator/src/main.ts @@ -7,13 +7,13 @@ import { join } from 'path'; import { BlockMetaInformation, + JayveeServices, PrimitiveValuetypes, createJayveeServices, getRegisteredConstraintMetaInformation, initializeWorkspace, isJayveeModel, } from '@jvalue/jayvee-language-server'; -import { LangiumDocuments } from 'langium'; import { NodeFileSystem } from 'langium/node'; import { UserDocGenerator } from './user-doc-generator'; @@ -23,18 +23,19 @@ async function main(): Promise { const services = createJayveeServices(NodeFileSystem).Jayvee; await initializeWorkspace(services); - const documentService = services.shared.workspace.LangiumDocuments; - generateBlockTypeDocs(documentService, rootPath); - generateConstraintTypeDocs(rootPath); - generateValueTypeDocs(rootPath); + generateBlockTypeDocs(services, rootPath); + generateConstraintTypeDocs(services, rootPath); + generateValueTypeDocs(services, rootPath); generateExampleDocs(rootPath); } function generateBlockTypeDocs( - documentService: LangiumDocuments, + services: JayveeServices, rootPath: string, ): void { + const documentService = services.shared.workspace.LangiumDocuments; + const metaInfs: BlockMetaInformation[] = []; documentService.all .map((document) => document.parseResult.value) @@ -48,6 +49,7 @@ function generateBlockTypeDocs( } }); }); + const docsPath = join( rootPath, 'apps', @@ -58,7 +60,7 @@ function generateBlockTypeDocs( ); for (const metaInf of metaInfs) { - const userDocBuilder = new UserDocGenerator(); + const userDocBuilder = new UserDocGenerator(services); const blockTypeDoc = userDocBuilder.generateBlockTypeDoc(metaInf); const fileName = `${metaInf.type}.md`; @@ -69,7 +71,10 @@ function generateBlockTypeDocs( } } -function generateConstraintTypeDocs(rootPath: string): void { +function generateConstraintTypeDocs( + services: JayveeServices, + rootPath: string, +): void { const docsPath = join( rootPath, 'apps', @@ -81,7 +86,7 @@ function generateConstraintTypeDocs(rootPath: string): void { 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`; @@ -92,9 +97,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); diff --git a/apps/docs/generator/src/user-doc-generator.ts b/apps/docs/generator/src/user-doc-generator.ts index f06920798..b62d8fb08 100644 --- a/apps/docs/generator/src/user-doc-generator.ts +++ b/apps/docs/generator/src/user-doc-generator.ts @@ -11,6 +11,7 @@ import { IOType, JayveeBlockTypeDocGenerator, JayveeConstraintTypeDocGenerator, + JayveeServices, JayveeValueTypesDocGenerator, MarkdownBuilder, PrimitiveValuetype, @@ -23,6 +24,8 @@ export class UserDocGenerator JayveeConstraintTypeDocGenerator, JayveeValueTypesDocGenerator { + constructor(private services: JayveeServices) {} + generateValueTypesDoc(valueTypes: { [name: string]: PrimitiveValuetype; }): string { @@ -73,12 +76,28 @@ block ExampleTableInterpreter oftype TableInterpreter { } generateBlockTypeDoc(metaInf: BlockMetaInformation): string { + const documentationService = + this.services.documentation.DocumentationProvider; + const blocktypeDocs = documentationService.getDocumentation( + metaInf.wrapped, + ); + const blocktypeDocsParts = blocktypeDocs + ?.split('@example') + .map((t) => t.trim()); + const blocktypeExamples = blocktypeDocsParts?.slice(1).map((x) => { + const exampleLines = x.split('\n'); + return { + description: exampleLines[0] ?? '', + code: exampleLines.slice(1).join('\n'), + }; + }); + const builder = new UserDocMarkdownBuilder() .docTitle(metaInf.type) .generationComment() .ioTypes(metaInf.inputType, metaInf.outputType) - .description(metaInf.docs.description) - .examples(metaInf.docs.examples); + .description(blocktypeDocsParts?.[0]) + .examples(blocktypeExamples); builder.propertiesHeading(); Object.entries(metaInf.getPropertySpecifications()).forEach( diff --git a/libs/language-server/src/lib/jayvee-module.ts b/libs/language-server/src/lib/jayvee-module.ts index 3e908a955..11c42c5db 100644 --- a/libs/language-server/src/lib/jayvee-module.ts +++ b/libs/language-server/src/lib/jayvee-module.ts @@ -23,6 +23,7 @@ import { JayveeCompletionProvider } from './completion/jayvee-completion-provide import { registerConstraints } from './constraint/constraint-registry'; import { JayveeHoverProvider } from './hover/jayvee-hover-provider'; import { JayveeValueConverter } from './jayvee-value-converter'; +import { JayveeDocumentationProvider } from './services/jayvee-documentation-provider'; import { RuntimeParameterProvider } from './services/runtime-parameter-provider'; import { JayveeValidationRegistry } from './validation/validation-registry'; @@ -67,6 +68,10 @@ export const JayveeModule: Module< new JayveeHoverProvider(services), }, RuntimeParameterProvider: () => new RuntimeParameterProvider(), + documentation: { + DocumentationProvider: (services: LangiumServices) => + new JayveeDocumentationProvider(services), + }, }; export const JayveeSharedModule: Module< diff --git a/libs/language-server/src/lib/meta-information/block-meta-inf.ts b/libs/language-server/src/lib/meta-information/block-meta-inf.ts index e2bf5f8ae..49d58616d 100644 --- a/libs/language-server/src/lib/meta-information/block-meta-inf.ts +++ b/libs/language-server/src/lib/meta-information/block-meta-inf.ts @@ -14,10 +14,7 @@ import { evaluateExpression, getIOType, } from '../ast'; -import { - ReferenceableBlocktypeDefinition, - isBuiltinBlocktypeDefinition, -} from '../ast/generated/ast'; +import { ReferenceableBlocktypeDefinition } from '../ast/generated/ast'; import { RuntimeParameterProvider } from '../services'; import { ExampleDoc, MetaInformation, PropertySpecification } from './meta-inf'; @@ -29,6 +26,7 @@ interface BlockDocs { export class BlockMetaInformation extends MetaInformation { docs: BlockDocs = {}; + readonly wrapped: ReferenceableBlocktypeDefinition; readonly inputType: IOType; readonly outputType: IOType; @@ -66,6 +64,8 @@ export class BlockMetaInformation extends MetaInformation { super(blocktypeName, properties, undefined); + this.wrapped = blocktypeDefinition; + const inputPort = blocktypeDefinition.inputs[0]; assert(inputPort !== undefined); this.inputType = getIOType(inputPort); @@ -100,9 +100,8 @@ export class BlockMetaInformation extends MetaInformation { } if ( - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition blocktypeDefinition.properties.some((property) => { - property.valueType.reference.ref === undefined; + return property.valueType.reference.ref === undefined; }) ) { return false; diff --git a/libs/language-server/src/lib/services/jayvee-documentation-provider.ts b/libs/language-server/src/lib/services/jayvee-documentation-provider.ts new file mode 100644 index 000000000..a2ce03c31 --- /dev/null +++ b/libs/language-server/src/lib/services/jayvee-documentation-provider.ts @@ -0,0 +1,15 @@ +import { AstNode, findCommentNode } from 'langium'; +import { JSDocDocumentationProvider } from 'langium/lib/documentation/documentation-provider'; + +export class JayveeDocumentationProvider extends JSDocDocumentationProvider { + override getDocumentation(node: AstNode): string | undefined { + const lastNode = findCommentNode( + node.$cstNode, + this.grammarConfig.multilineCommentRules, + ); + if (lastNode === undefined) { + return; + } + return lastNode.text.replace('/*', '').replace('*/', ''); + } +} diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv index 8f2337c4e..9278962ee 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv @@ -3,8 +3,8 @@ Interprets an input file as a csv-file containing string-values delimited by `de @example Interprets an input file as a csv-file containing string-values delimited by `;` and outputs `Sheet`. block AgencyCSVInterpreter oftype CSVInterpreter { - delimiter: ";"; - } + delimiter: ";"; +} */ builtin blocktype CSVInterpreter { input default oftype TextFile; diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv index 62aa8d7b9..99b9df632 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv @@ -11,53 +11,52 @@ builtin blocktype GtfsRTInterpreter { output default oftype Sheet; // Entity to process from GTFS-RT-feed (`trip_update`, `alert` or `vehicle`). - // We currently support following Output-Sheets, each are an equivalent to the flattened Element Index defined in (just required fields are included)): - // - // Entity TripUpdate: - // ``` - // [ - // 'header.gtfs_realtime_version', - // 'header.timestamp', - // 'header.incrementality', - // 'entity.id', - // 'entity.trip_update.trip.trip_id', - // 'entity.trip_update.trip.route_id', - // 'entity.trip_update.stop_time_update.stop_sequence', - // 'entity.trip_update.stop_time_update.stop_id', - // 'entity.trip_update.stop_time_update.arrival.time', - // 'entity.trip_update.stop_time_update.departure.time', - // ]; - // - // ``` - // Entity VehiclePosition: - // ``` - // [ - // 'header.gtfs_realtime_version', - // 'header.timestamp', - // 'header.incrementality', - // 'entity.id', - // 'entity.vehicle_position.vehicle_descriptor.id', - // 'entity.vehicle_position.trip.trip_id', - // 'entity.vehicle_position.trip.route_id', - // 'entity.vehicle_position.position.latitude', - // 'entity.vehicle_position.position.longitude', - // 'entity.vehicle_position.timestamp', - // ]; - // ``` - // - // Entity Alert: - // ``` - // [ - // 'header.gtfs_realtime_version', - // 'header.timestamp', - // 'header.incrementality', - // 'entity.id', - // 'entity.alert.informed_entity.route_id', - // 'entity.alert.header_text', - // 'entity.alert.description_text', - // ]; - // ``` - // - // + // + // We currently support following Output-Sheets, each are an equivalent to the flattened Element Index defined in (just required fields are included): + // + // Entity TripUpdate: + // ``` + // [ + // 'header.gtfs_realtime_version', + // 'header.timestamp', + // 'header.incrementality', + // 'entity.id', + // 'entity.trip_update.trip.trip_id', + // 'entity.trip_update.trip.route_id', + // 'entity.trip_update.stop_time_update.stop_sequence', + // 'entity.trip_update.stop_time_update.stop_id', + // 'entity.trip_update.stop_time_update.arrival.time', + // 'entity.trip_update.stop_time_update.departure.time', + // ]; + + // ``` + // Entity VehiclePosition: + // ``` + // [ + // 'header.gtfs_realtime_version', + // 'header.timestamp', + // 'header.incrementality', + // 'entity.id', + // 'entity.vehicle_position.vehicle_descriptor.id', + // 'entity.vehicle_position.trip.trip_id', + // 'entity.vehicle_position.trip.route_id', + // 'entity.vehicle_position.position.latitude', + // 'entity.vehicle_position.position.longitude', + // 'entity.vehicle_position.timestamp', + // ]; + // ``` + + // Entity Alert: + // ``` + // [ + // 'header.gtfs_realtime_version', + // 'header.timestamp', + // 'header.incrementality', + // 'entity.id', + // 'entity.alert.informed_entity.route_id', + // 'entity.alert.header_text', + // 'entity.alert.description_text', + // ]; + // ``` property entity oftype text; } From 55abaa612c263fb854198eb60320a0aeee86c0cb Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 17:53:28 +0200 Subject: [PATCH 31/43] Add documentation for properties of blocktypes reading from jv comment --- apps/docs/generator/src/user-doc-generator.ts | 25 ++++- .../builtin-blocktypes/ArchiveInterpreter.jv | 4 +- .../builtin-blocktypes/CellRangeSelector.jv | 4 +- .../stdlib/builtin-blocktypes/CellWriter.jv | 8 +- .../builtin-blocktypes/ColumnDeleter.jv | 4 +- .../builtin-blocktypes/CsvInterpreter.jv | 14 ++- .../stdlib/builtin-blocktypes/FilePicker.jv | 4 +- .../builtin-blocktypes/GtfsRtInterpreter.jv | 94 ++++++++++--------- .../builtin-blocktypes/HttpExtractor.jv | 24 ++++- .../builtin-blocktypes/PostgresLoader.jv | 29 ++++-- .../stdlib/builtin-blocktypes/RowDeleter.jv | 4 +- .../stdlib/builtin-blocktypes/SheetPicker.jv | 4 +- .../stdlib/builtin-blocktypes/SqliteLoader.jv | 14 ++- .../builtin-blocktypes/TableInterpreter.jv | 13 ++- .../builtin-blocktypes/TableTransformer.jv | 20 ++-- .../builtin-blocktypes/TextFileInterpreter.jv | 9 +- .../builtin-blocktypes/TextLineDeleter.jv | 4 +- 17 files changed, 192 insertions(+), 86 deletions(-) diff --git a/apps/docs/generator/src/user-doc-generator.ts b/apps/docs/generator/src/user-doc-generator.ts index b62d8fb08..ecd494cb7 100644 --- a/apps/docs/generator/src/user-doc-generator.ts +++ b/apps/docs/generator/src/user-doc-generator.ts @@ -102,12 +102,33 @@ block ExampleTableInterpreter oftype TableInterpreter { builder.propertiesHeading(); Object.entries(metaInf.getPropertySpecifications()).forEach( ([key, property]) => { + const blocktypeProperty = metaInf.wrapped.properties.filter( + (p) => p.name === key, + )[0]; + if (blocktypeProperty === undefined) { + return; + } + + const propertyDocs = + documentationService.getDocumentation(blocktypeProperty); + console.log(propertyDocs); + const propertyDocsParts = propertyDocs + ?.split('@example') + .map((t) => t.trim()); + const propertyExamples = propertyDocsParts?.slice(1).map((x) => { + const exampleLines = x.split('\n'); + return { + description: exampleLines[0] ?? '', + code: exampleLines.slice(1).join('\n'), + }; + }); + builder .propertyHeading(key, 3) .propertySpec(property) - .description(property.docs?.description, 4) + .description(propertyDocsParts?.[0], 4) .validation(property.docs?.validation, 4) - .examples(property.docs?.examples, 4); + .examples(propertyExamples, 4); }, ); diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv index 42d275fda..361e11ef8 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv @@ -10,6 +10,8 @@ builtin blocktype ArchiveInterpreter { input default oftype File; output default oftype FileSystem; - // The archive type to be interpreted, e.g., "zip" or "gz". + /* + The archive type to be interpreted, e.g., "zip" or "gz". + */ property archiveType oftype text; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv index 2f8ddd5eb..c935540a9 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv @@ -10,6 +10,8 @@ builtin blocktype CellRangeSelector { input default oftype Sheet; output default oftype Sheet; - // The cell range to select. + /* + The cell range to select. + */ property select oftype CellRange; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv index 87be6bd30..a70ca8a5d 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv @@ -17,8 +17,12 @@ builtin blocktype CellWriter { input default oftype Sheet; output default oftype Sheet; - // The values to write. + /* + The values to write. + */ property write oftype Collection; - // The cells to write into. + /* + The cells to write into. + */ property at oftype CellRange; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv index 1733bb04c..2631c51ba 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv @@ -10,6 +10,8 @@ builtin blocktype ColumnDeleter { input default oftype Sheet; output default oftype Sheet; - // The columns to delete. Has to be a full column. + /* + The columns to delete. Has to be a full column. + */ property delete oftype Collection; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv index 9278962ee..479e8006c 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv @@ -10,10 +10,18 @@ builtin blocktype CSVInterpreter { input default oftype TextFile; output default oftype Sheet; - // The delimiter for values in the CSV file. + /* + The delimiter for values in the CSV file. + */ property delimiter oftype text: ','; - // The enclosing character that may be used for values in the CSV file. + + /* + The enclosing character that may be used for values in the CSV file. + */ property enclosing oftype text: ''; - // The character to escape enclosing characters in values. + + /* + The character to escape enclosing characters in values. + */ property enclosingEscape oftype text: ''; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv b/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv index 4cb18c9ce..e06d8c46b 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv @@ -10,6 +10,8 @@ builtin blocktype FilePicker { input default oftype FileSystem; output default oftype File; - // The path of the file to select, relative to the root of the provided `FileSystem`. + /* + The path of the file to select, relative to the root of the provided `FileSystem`. + */ property path oftype text; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv index 99b9df632..e373524a2 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv @@ -10,53 +10,55 @@ builtin blocktype GtfsRTInterpreter { input default oftype File; output default oftype Sheet; - // Entity to process from GTFS-RT-feed (`trip_update`, `alert` or `vehicle`). - // - // We currently support following Output-Sheets, each are an equivalent to the flattened Element Index defined in (just required fields are included): - // - // Entity TripUpdate: - // ``` - // [ - // 'header.gtfs_realtime_version', - // 'header.timestamp', - // 'header.incrementality', - // 'entity.id', - // 'entity.trip_update.trip.trip_id', - // 'entity.trip_update.trip.route_id', - // 'entity.trip_update.stop_time_update.stop_sequence', - // 'entity.trip_update.stop_time_update.stop_id', - // 'entity.trip_update.stop_time_update.arrival.time', - // 'entity.trip_update.stop_time_update.departure.time', - // ]; + /* + Entity to process from GTFS-RT-feed (`trip_update`, `alert` or `vehicle`). + + We currently support following Output-Sheets, each are an equivalent to the flattened Element Index defined in (just required fields are included): + + Entity TripUpdate: + ``` + [ + 'header.gtfs_realtime_version', + 'header.timestamp', + 'header.incrementality', + 'entity.id', + 'entity.trip_update.trip.trip_id', + 'entity.trip_update.trip.route_id', + 'entity.trip_update.stop_time_update.stop_sequence', + 'entity.trip_update.stop_time_update.stop_id', + 'entity.trip_update.stop_time_update.arrival.time', + 'entity.trip_update.stop_time_update.departure.time', + ]; - // ``` - // Entity VehiclePosition: - // ``` - // [ - // 'header.gtfs_realtime_version', - // 'header.timestamp', - // 'header.incrementality', - // 'entity.id', - // 'entity.vehicle_position.vehicle_descriptor.id', - // 'entity.vehicle_position.trip.trip_id', - // 'entity.vehicle_position.trip.route_id', - // 'entity.vehicle_position.position.latitude', - // 'entity.vehicle_position.position.longitude', - // 'entity.vehicle_position.timestamp', - // ]; - // ``` + ``` + Entity VehiclePosition: + ``` + [ + 'header.gtfs_realtime_version', + 'header.timestamp', + 'header.incrementality', + 'entity.id', + 'entity.vehicle_position.vehicle_descriptor.id', + 'entity.vehicle_position.trip.trip_id', + 'entity.vehicle_position.trip.route_id', + 'entity.vehicle_position.position.latitude', + 'entity.vehicle_position.position.longitude', + 'entity.vehicle_position.timestamp', + ]; + ``` - // Entity Alert: - // ``` - // [ - // 'header.gtfs_realtime_version', - // 'header.timestamp', - // 'header.incrementality', - // 'entity.id', - // 'entity.alert.informed_entity.route_id', - // 'entity.alert.header_text', - // 'entity.alert.description_text', - // ]; - // ``` + Entity Alert: + ``` + [ + 'header.gtfs_realtime_version', + 'header.timestamp', + 'header.incrementality', + 'entity.id', + 'entity.alert.informed_entity.route_id', + 'entity.alert.header_text', + 'entity.alert.description_text', + ]; + ``` + */ property entity oftype text; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv index 35983ba28..a80444744 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv @@ -10,14 +10,28 @@ builtin blocktype HttpExtractor { input default oftype None; output default oftype File; - // The URL to the file in the web to extract. + /* + The URL to the file in the web to extract. + */ property url oftype text; - // Configures how many retries should be executed after a failure fetching the data. + + /* + Configures how many retries should be executed after a failure fetching the data. + */ property retries oftype integer: 0; - // Configures the wait time in milliseconds before executing a retry. + + /* + Configures the wait time in milliseconds before executing a retry. + */ property retryBackoffMilliseconds oftype integer: 1000; - // Configures the wait strategy before executing a retry. Can have values "exponential" or "linear". + + /* + Configures the wait strategy before executing a retry. Can have values "exponential" or "linear". + */ property retryBackoffStrategy oftype text: "exponential"; - // Indicates, whether to follow redirects on get requests. If `false`, redirects are not followed. Default `true` + + /* + Indicates, whether to follow redirects on get requests. If `false`, redirects are not followed. Default `true` + */ property followRedirects oftype boolean: true; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv b/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv index ca41e29aa..cf3f86d79 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv @@ -15,16 +15,33 @@ builtin blocktype PostgresLoader { input default oftype Table; output default oftype None; - // The hostname or IP address of the Postgres database. + /* + The hostname or IP address of the Postgres database. + */ property host oftype text; - // The port of the Postgres database. + + /* + The port of the Postgres database. + */ property port oftype integer; - // The username to login to the Postgres database. + + /* + The username to login to the Postgres database. + */ property username oftype text; - // The password to login to the Postgres database. + + /* + The password to login to the Postgres database. + */ property password oftype text; - // The database to use. + + /* + The database to use. + */ property database oftype text; - // The name of the table to write into. + + /* + The name of the table to write into. + */ property table oftype text; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv index 16f0b7b4a..a12e92b56 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv @@ -10,6 +10,8 @@ builtin blocktype RowDeleter { input default oftype Sheet; output default oftype Sheet; - // The rows to delete. + /* + The rows to delete. + */ property delete oftype Collection; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv b/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv index 28022d5c7..6edfd87c3 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv @@ -10,6 +10,8 @@ builtin blocktype SheetPicker { input default oftype Workbook; output default oftype Sheet; - // The name of the sheet to select. + /* + The name of the sheet to select. + */ property sheetName oftype text; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv b/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv index 477b3fb78..4a3d372a9 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv @@ -11,10 +11,18 @@ builtin blocktype SQLiteLoader { input default oftype Table; output default oftype None; - // The name of the table to write into. + /* + The name of the table to write into. + */ property table oftype text; - // The path to a SQLite file that will be created if it does not exist. Usual file extensions are `.sqlite` and `.db`. + + /* + The path to a SQLite file that will be created if it does not exist. Usual file extensions are `.sqlite` and `.db`. + */ property file oftype text; - // Indicates, whether to drop the table before loading data into it. If `false`, data is appended to the table instead of dropping it. + + /* + Indicates, whether to drop the table before loading data into it. If `false`, data is appended to the table instead of dropping it. + */ property dropTable oftype boolean: true; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv index a9a028ca5..6669f6b1d 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv @@ -25,8 +25,13 @@ builtin blocktype TableInterpreter { input default oftype Sheet; output default oftype Table; - // Whether the first row should be interpreted as header row. - property header oftype boolean: true; - // Collection of valuetype assignments. Uses column names (potentially matched with the header or by sequence depending on the `header` property) to assign a primitive valuetype to each column. - property columns oftype Collection; + /* + Whether the first row should be interpreted as header row. + */ + property header oftype boolean: true; + + /* + Collection of valuetype assignments. Uses column names (potentially matched with the header or by sequence depending on the `header` property) to assign a primitive valuetype to each column. + */ + property columns oftype Collection; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv index 0afc735a9..c96bae02c 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv @@ -35,10 +35,18 @@ builtin blocktype TableTransformer { input default oftype Table; output default oftype Table; - // The names of the input columns. The columns have to be present in the table and match with the transform's input port types. - property inputColumns oftype Collection; - // The name of the output column. Overwrites the column if it already exists, or otherwise creates a new one. - property outputColumn oftype text; - // Reference to the transform that is applied to the column. - property use oftype Transform; + /* + The names of the input columns. The columns have to be present in the table and match with the transform's input port types. + */ + property inputColumns oftype Collection; + + /* + The name of the output column. Overwrites the column if it already exists, or otherwise creates a new one. + */ + property outputColumn oftype text; + + /* + Reference to the transform that is applied to the column. + */ + property use oftype Transform; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv index e2c4c0d14..fdfe50e06 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv @@ -5,8 +5,13 @@ builtin blocktype TextFileInterpreter { input default oftype File; output default oftype TextFile; - // The encoding used for decoding the file contents. + /* + The encoding used for decoding the file contents. + */ property encoding oftype text: 'utf-8'; - // The regex for identifying line breaks. + + /* + The regex for identifying line breaks. + */ property lineBreak oftype Regex: /\r?\n/; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv index bdf050cbf..8a6da0446 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv @@ -5,6 +5,8 @@ builtin blocktype TextLineDeleter { input default oftype TextFile; output default oftype TextFile; - // The line numbers to delete. + /* + The line numbers to delete. + */ property lines oftype Collection; } From ca72b288d838a7aadad72c1518f13571c88102cf Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 18:03:23 +0200 Subject: [PATCH 32/43] Pull out method extractDocsFromComment --- apps/docs/generator/src/user-doc-generator.ts | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/apps/docs/generator/src/user-doc-generator.ts b/apps/docs/generator/src/user-doc-generator.ts index ecd494cb7..d7aa9dde4 100644 --- a/apps/docs/generator/src/user-doc-generator.ts +++ b/apps/docs/generator/src/user-doc-generator.ts @@ -81,23 +81,15 @@ block ExampleTableInterpreter oftype TableInterpreter { const blocktypeDocs = documentationService.getDocumentation( metaInf.wrapped, ); - const blocktypeDocsParts = blocktypeDocs - ?.split('@example') - .map((t) => t.trim()); - const blocktypeExamples = blocktypeDocsParts?.slice(1).map((x) => { - const exampleLines = x.split('\n'); - return { - description: exampleLines[0] ?? '', - code: exampleLines.slice(1).join('\n'), - }; - }); + const blocktypeDocsFromComments = + this.extractDocsFromComment(blocktypeDocs); const builder = new UserDocMarkdownBuilder() .docTitle(metaInf.type) .generationComment() .ioTypes(metaInf.inputType, metaInf.outputType) - .description(blocktypeDocsParts?.[0]) - .examples(blocktypeExamples); + .description(blocktypeDocsFromComments?.description) + .examples(blocktypeDocsFromComments?.examples); builder.propertiesHeading(); Object.entries(metaInf.getPropertySpecifications()).forEach( @@ -111,24 +103,14 @@ block ExampleTableInterpreter oftype TableInterpreter { const propertyDocs = documentationService.getDocumentation(blocktypeProperty); - console.log(propertyDocs); - const propertyDocsParts = propertyDocs - ?.split('@example') - .map((t) => t.trim()); - const propertyExamples = propertyDocsParts?.slice(1).map((x) => { - const exampleLines = x.split('\n'); - return { - description: exampleLines[0] ?? '', - code: exampleLines.slice(1).join('\n'), - }; - }); + const propDocsFromComments = this.extractDocsFromComment(propertyDocs); builder .propertyHeading(key, 3) .propertySpec(property) - .description(propertyDocsParts?.[0], 4) + .description(propDocsFromComments?.description, 4) .validation(property.docs?.validation, 4) - .examples(propertyExamples, 4); + .examples(propDocsFromComments?.examples, 4); }, ); @@ -157,6 +139,30 @@ block ExampleTableInterpreter oftype TableInterpreter { return builder.build(); } + + private extractDocsFromComment(comment?: string | undefined): + | { + description: string | undefined; + examples: ExampleDoc[]; + } + | undefined { + if (comment === undefined) { + return undefined; + } + const commentSections = comment.split('@example').map((t) => t.trim()); + const examples = commentSections.slice(1).map((x) => { + const exampleLines = x.split('\n'); + return { + description: exampleLines[0] ?? '', + code: exampleLines.slice(1).join('\n'), + }; + }); + + return { + description: commentSections[0], + examples: examples, + }; + } } class UserDocMarkdownBuilder { From d0ad92904c8f037971b03c7ca6ee355c7072e9c1 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 7 Sep 2023 18:20:38 +0200 Subject: [PATCH 33/43] Improve assertion messages --- .../src/lib/constraints/constraint-executor-registry.ts | 5 ++++- libs/execution/src/lib/execution-context.ts | 7 ++++++- libs/interpreter-lib/src/parsing-util.ts | 1 - 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libs/execution/src/lib/constraints/constraint-executor-registry.ts b/libs/execution/src/lib/constraints/constraint-executor-registry.ts index 2929f230b..b7c9f753f 100644 --- a/libs/execution/src/lib/constraints/constraint-executor-registry.ts +++ b/libs/execution/src/lib/constraints/constraint-executor-registry.ts @@ -47,7 +47,10 @@ export function createConstraintExecutor( ): ConstraintExecutor { if (isTypedConstraintDefinition(constraint)) { const constraintType = constraint.type.ref?.name; - assert(constraintType !== undefined); + assert( + constraintType !== undefined, + `Could not resolve constraint type of constraint ${constraint.name}`, + ); const constraintExecutor = constraintExecutorRegistry.get(constraintType); assert( constraintExecutor !== undefined, diff --git a/libs/execution/src/lib/execution-context.ts b/libs/execution/src/lib/execution-context.ts index 8253fcc44..baa2a31f0 100644 --- a/libs/execution/src/lib/execution-context.ts +++ b/libs/execution/src/lib/execution-context.ts @@ -150,7 +150,12 @@ export class ExecutionContext { return getOrFailConstraintMetaInf(currentNode.type); } else if (isBlockDefinition(currentNode)) { assert(isReference(currentNode.type)); - assert(BlockMetaInformation.canBeWrapped(currentNode.type)); + assert( + BlockMetaInformation.canBeWrapped(currentNode.type), + `Blocktype ${ + currentNode.type.ref?.name ?? '' + } cannot be wrapped`, + ); return new BlockMetaInformation(currentNode.type); } assertUnreachable(currentNode); diff --git a/libs/interpreter-lib/src/parsing-util.ts b/libs/interpreter-lib/src/parsing-util.ts index 1268e3d1d..a08029a09 100644 --- a/libs/interpreter-lib/src/parsing-util.ts +++ b/libs/interpreter-lib/src/parsing-util.ts @@ -79,7 +79,6 @@ export async function validateDocument( for (const errDiagnostic of errDiagnostics) { logger.logLanguageServerDiagnostic(errDiagnostic, document); } - throw new Error(errDiagnostics.map((r) => r.message).join('\n')); process.exit(ExitCode.FAILURE); } From 9acd943b67ea7f8ee753861c3b6ff2ac56172d81 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 26 Sep 2023 14:12:07 +0200 Subject: [PATCH 34/43] Use default JSdocProvider --- apps/docs/generator/src/user-doc-generator.ts | 13 +- libs/language-server/src/lib/jayvee-module.ts | 5 - .../src/stdlib/CSVExtractor.jv | 4 +- .../src/stdlib/GTFSExtractor.jv | 4 +- .../builtin-blocktypes/ArchiveInterpreter.jv | 18 +-- .../builtin-blocktypes/CellRangeSelector.jv | 18 +-- .../stdlib/builtin-blocktypes/CellWriter.jv | 37 +++--- .../builtin-blocktypes/ColumnDeleter.jv | 18 +-- .../builtin-blocktypes/CsvInterpreter.jv | 26 ++-- .../stdlib/builtin-blocktypes/FilePicker.jv | 18 +-- .../builtin-blocktypes/GtfsRtInterpreter.jv | 112 +++++++++--------- .../builtin-blocktypes/HttpExtractor.jv | 34 +++--- .../builtin-blocktypes/PostgresLoader.jv | 48 ++++---- .../stdlib/builtin-blocktypes/RowDeleter.jv | 18 +-- .../stdlib/builtin-blocktypes/SheetPicker.jv | 18 +-- .../stdlib/builtin-blocktypes/SqliteLoader.jv | 28 ++--- .../builtin-blocktypes/TableInterpreter.jv | 52 ++++---- .../builtin-blocktypes/TableTransformer.jv | 76 ++++++------ .../builtin-blocktypes/TextFileInterpreter.jv | 12 +- .../builtin-blocktypes/TextLineDeleter.jv | 8 +- .../builtin-blocktypes/TextRangeSelector.jv | 4 +- .../builtin-blocktypes/XlsInterpreter.jv | 11 +- 22 files changed, 296 insertions(+), 286 deletions(-) diff --git a/apps/docs/generator/src/user-doc-generator.ts b/apps/docs/generator/src/user-doc-generator.ts index d7aa9dde4..5cfa4c0d4 100644 --- a/apps/docs/generator/src/user-doc-generator.ts +++ b/apps/docs/generator/src/user-doc-generator.ts @@ -149,7 +149,18 @@ block ExampleTableInterpreter oftype TableInterpreter { if (comment === undefined) { return undefined; } - const commentSections = comment.split('@example').map((t) => t.trim()); + /* + Format: + + + *@example* + + + */ + + const commentSections = comment + .split('*@example*') + .map((section) => section.trim()); const examples = commentSections.slice(1).map((x) => { const exampleLines = x.split('\n'); return { diff --git a/libs/language-server/src/lib/jayvee-module.ts b/libs/language-server/src/lib/jayvee-module.ts index 11c42c5db..3e908a955 100644 --- a/libs/language-server/src/lib/jayvee-module.ts +++ b/libs/language-server/src/lib/jayvee-module.ts @@ -23,7 +23,6 @@ import { JayveeCompletionProvider } from './completion/jayvee-completion-provide import { registerConstraints } from './constraint/constraint-registry'; import { JayveeHoverProvider } from './hover/jayvee-hover-provider'; import { JayveeValueConverter } from './jayvee-value-converter'; -import { JayveeDocumentationProvider } from './services/jayvee-documentation-provider'; import { RuntimeParameterProvider } from './services/runtime-parameter-provider'; import { JayveeValidationRegistry } from './validation/validation-registry'; @@ -68,10 +67,6 @@ export const JayveeModule: Module< new JayveeHoverProvider(services), }, RuntimeParameterProvider: () => new RuntimeParameterProvider(), - documentation: { - DocumentationProvider: (services: LangiumServices) => - new JayveeDocumentationProvider(services), - }, }; export const JayveeSharedModule: Module< diff --git a/libs/language-server/src/stdlib/CSVExtractor.jv b/libs/language-server/src/stdlib/CSVExtractor.jv index 20b987219..29c88be6f 100644 --- a/libs/language-server/src/stdlib/CSVExtractor.jv +++ b/libs/language-server/src/stdlib/CSVExtractor.jv @@ -2,7 +2,9 @@ // // SPDX-License-Identifier: AGPL-3.0-only -// A CSVExtractor extracts a file from a given URL and interprets it as CSV +/** +* A CSVExtractor extracts a file from a given URL and interprets it as CSV +*/ composite blocktype CSVExtractor { property url oftype text; property delimiter oftype text: ','; diff --git a/libs/language-server/src/stdlib/GTFSExtractor.jv b/libs/language-server/src/stdlib/GTFSExtractor.jv index 475065315..b1741e36a 100644 --- a/libs/language-server/src/stdlib/GTFSExtractor.jv +++ b/libs/language-server/src/stdlib/GTFSExtractor.jv @@ -2,7 +2,9 @@ // // SPDX-License-Identifier: AGPL-3.0-only -// A GTFSExtractor extracts a file from a given URL, interprets it as ZIP and extracts it +/** +* A GTFSExtractor extracts a file from a given URL, interprets it as ZIP and extracts it +*/ composite blocktype GTFSExtractor { property url oftype text; diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv index 361e11ef8..21ea227ce 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv @@ -1,17 +1,17 @@ -/* -Interprets a `File` as an archive file and converts it to a `FileSystem`. The archive file root is considered the root of the `FileSystem`. - -@example Interprets a `File` as a ZIP-archive and creates a `FileSystem` of its extracted contents. -block ZipArchiveInterpreter oftype ArchiveInterpreter { - archiveType: "zip"; -} +/** +* Interprets a `File` as an archive file and converts it to a `FileSystem`. The archive file root is considered the root of the `FileSystem`. +* +* @example Interprets a `File` as a ZIP-archive and creates a `FileSystem` of its extracted contents. +* block ZipArchiveInterpreter oftype ArchiveInterpreter { +* archiveType: "zip"; +* } */ builtin blocktype ArchiveInterpreter { input default oftype File; output default oftype FileSystem; - /* - The archive type to be interpreted, e.g., "zip" or "gz". + /** + * The archive type to be interpreted, e.g., "zip" or "gz". */ property archiveType oftype text; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv index c935540a9..b725f8c1a 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv @@ -1,17 +1,17 @@ -/* -Selects a subset of a `Sheet` to produce a new `Sheet`. - -@example Selects the cells in the given range and produces a new `Sheet` containing only the selected cells. -block CarsCoreDataSelector oftype CellRangeSelector { - select: range A1:E*; -} +/** +* Selects a subset of a `Sheet` to produce a new `Sheet`. +* +* @example Selects the cells in the given range and produces a new `Sheet` containing only the selected cells. +* block CarsCoreDataSelector oftype CellRangeSelector { +* select: range A1:E*; +* } */ builtin blocktype CellRangeSelector { input default oftype Sheet; output default oftype Sheet; - /* - The cell range to select. + /** + * The cell range to select. */ property select oftype CellRange; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv index a70ca8a5d..8d4407554 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv @@ -1,28 +1,29 @@ -/* -Writes textual values into cells of a `Sheet`. The number of text values needs to match the number of cells to write into. - -@example Write the value "Name" into cell `A1`. -block NameHeaderWriter oftype CellWriter { - at: cell A1; - write: ["Name"]; -} - -@example Write the values "Name", "Age" into cells `A1` and `A2`. -block HeaderSequenceWriter oftype CellWriter { - at: range A1:A2; - write: ["Name", "Age"]; -} +/** +* Writes textual values into cells of a `Sheet`. The number of text values needs to match the number of cells to write into. +* +* @example Write the value "Name" into cell `A1`. +* block NameHeaderWriter oftype CellWriter { +* at: cell A1; +* write: ["Name"]; +* } +* +* @example Write the values "Name", "Age" into cells `A1` and `A2`. +* block HeaderSequenceWriter oftype CellWriter { +* at: range A1:A2; +* write: ["Name", "Age"]; +* } */ builtin blocktype CellWriter { input default oftype Sheet; output default oftype Sheet; - /* - The values to write. + /** + * The values to write. */ property write oftype Collection; - /* - The cells to write into. + + /** + * The cells to write into. */ property at oftype CellRange; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv index 2631c51ba..d3f15f5e7 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv @@ -1,17 +1,17 @@ -/* -Deletes columns from a `Sheet`. Column IDs of subsequent columns will be shifted accordingly, so there will be no gaps. - -@example Deletes column B (i.e. the second column). -block MpgColumnDeleter oftype ColumnDeleter { - delete: [column B]; -} +/** +* Deletes columns from a `Sheet`. Column IDs of subsequent columns will be shifted accordingly, so there will be no gaps. +* +* @example Deletes column B (i.e. the second column). +* block MpgColumnDeleter oftype ColumnDeleter { +* delete: [column B]; +* } */ builtin blocktype ColumnDeleter { input default oftype Sheet; output default oftype Sheet; - /* - The columns to delete. Has to be a full column. + /** + * The columns to delete. Has to be a full column. */ property delete oftype Collection; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv index 479e8006c..3c4fb3d61 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv @@ -1,27 +1,27 @@ -/* -Interprets an input file as a csv-file containing string-values delimited by `delimiter` and outputs a `Sheet`. - -@example Interprets an input file as a csv-file containing string-values delimited by `;` and outputs `Sheet`. -block AgencyCSVInterpreter oftype CSVInterpreter { - delimiter: ";"; -} +/** +* Interprets an input file as a csv-file containing string-values delimited by `delimiter` and outputs a `Sheet`. +* +* @example Interprets an input file as a csv-file containing string-values delimited by `;` and outputs `Sheet`. +* block AgencyCSVInterpreter oftype CSVInterpreter { +* delimiter: ";"; +* } */ builtin blocktype CSVInterpreter { input default oftype TextFile; output default oftype Sheet; - /* - The delimiter for values in the CSV file. + /** + * The delimiter for values in the CSV file. */ property delimiter oftype text: ','; - /* - The enclosing character that may be used for values in the CSV file. + /** + * The enclosing character that may be used for values in the CSV file. */ property enclosing oftype text: ''; - /* - The character to escape enclosing characters in values. + /** + * The character to escape enclosing characters in values. */ property enclosingEscape oftype text: ''; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv b/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv index e06d8c46b..cd4d8ca25 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv @@ -1,17 +1,17 @@ -/* -Selects one `File` from a `FileSystem` based on its relative path to the root of the `FileSystem`. If no file matches the relative path, no output is created and the execution of the pipeline is aborted. - -@example Tries to pick the file `agency.txt` from the root of the provided `FileSystem`. If `agency.txt` exists it is passed on as `File`, if it does not exist the execution of the pipeline is aborted. -block AgencyFilePicker oftype FilePicker { - path: "./agency.txt"; -} +/** +* Selects one `File` from a `FileSystem` based on its relative path to the root of the `FileSystem`. If no file matches the relative path, no output is created and the execution of the pipeline is aborted. +* +* @example Tries to pick the file `agency.txt` from the root of the provided `FileSystem`. If `agency.txt` exists it is passed on as `File`, if it does not exist the execution of the pipeline is aborted. +* block AgencyFilePicker oftype FilePicker { +* path: "./agency.txt"; +* } */ builtin blocktype FilePicker { input default oftype FileSystem; output default oftype File; - /* - The path of the file to select, relative to the root of the provided `FileSystem`. + /** + * The path of the file to select, relative to the root of the provided `FileSystem`. */ property path oftype text; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv index e373524a2..f77cd71a7 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv @@ -1,64 +1,64 @@ -/* -Interprets an protobuf file (binary) of type `File` by decoding the file according to `gtfs-realtime.proto`. Outputs the extracted entity defined by `entity` as a `Sheet` - -@example A file is interpretet as an GTFS-RT file, which contains TripUpdate. -block GtfsRTTripUpdateInterpreter oftype GtfsRTInterpreter{ - entity: "trip_update"; -} +/** +* Interprets an protobuf file (binary) of type `File` by decoding the file according to `gtfs-realtime.proto`. Outputs the extracted entity defined by `entity` as a `Sheet` +* +* @example A file is interpretet as an GTFS-RT file, which contains TripUpdate. +* block GtfsRTTripUpdateInterpreter oftype GtfsRTInterpreter{ +* entity: "trip_update"; +* } */ builtin blocktype GtfsRTInterpreter { input default oftype File; output default oftype Sheet; - /* - Entity to process from GTFS-RT-feed (`trip_update`, `alert` or `vehicle`). - - We currently support following Output-Sheets, each are an equivalent to the flattened Element Index defined in (just required fields are included): - - Entity TripUpdate: - ``` - [ - 'header.gtfs_realtime_version', - 'header.timestamp', - 'header.incrementality', - 'entity.id', - 'entity.trip_update.trip.trip_id', - 'entity.trip_update.trip.route_id', - 'entity.trip_update.stop_time_update.stop_sequence', - 'entity.trip_update.stop_time_update.stop_id', - 'entity.trip_update.stop_time_update.arrival.time', - 'entity.trip_update.stop_time_update.departure.time', - ]; - - ``` - Entity VehiclePosition: - ``` - [ - 'header.gtfs_realtime_version', - 'header.timestamp', - 'header.incrementality', - 'entity.id', - 'entity.vehicle_position.vehicle_descriptor.id', - 'entity.vehicle_position.trip.trip_id', - 'entity.vehicle_position.trip.route_id', - 'entity.vehicle_position.position.latitude', - 'entity.vehicle_position.position.longitude', - 'entity.vehicle_position.timestamp', - ]; - ``` - - Entity Alert: - ``` - [ - 'header.gtfs_realtime_version', - 'header.timestamp', - 'header.incrementality', - 'entity.id', - 'entity.alert.informed_entity.route_id', - 'entity.alert.header_text', - 'entity.alert.description_text', - ]; - ``` + /** + * Entity to process from GTFS-RT-feed (`trip_update`, `alert` or `vehicle`). + * + * We currently support following Output-Sheets, each are an equivalent to the flattened Element Index defined in (just required fields are included): + * + * Entity TripUpdate: + * ``` + * [ + * 'header.gtfs_realtime_version', + * 'header.timestamp', + * 'header.incrementality', + * 'entity.id', + * 'entity.trip_update.trip.trip_id', + * 'entity.trip_update.trip.route_id', + * 'entity.trip_update.stop_time_update.stop_sequence', + * 'entity.trip_update.stop_time_update.stop_id', + * 'entity.trip_update.stop_time_update.arrival.time', + * 'entity.trip_update.stop_time_update.departure.time', + * ]; + * + * ``` + * Entity VehiclePosition: + * ``` + * [ + * 'header.gtfs_realtime_version', + * 'header.timestamp', + * 'header.incrementality', + * 'entity.id', + * 'entity.vehicle_position.vehicle_descriptor.id', + * 'entity.vehicle_position.trip.trip_id', + * 'entity.vehicle_position.trip.route_id', + * 'entity.vehicle_position.position.latitude', + * 'entity.vehicle_position.position.longitude', + * 'entity.vehicle_position.timestamp', + * ]; + * ``` + * + * Entity Alert: + * ``` + * [ + * 'header.gtfs_realtime_version', + * 'header.timestamp', + * 'header.incrementality', + * 'entity.id', + * 'entity.alert.informed_entity.route_id', + * 'entity.alert.header_text', + * 'entity.alert.description_text', + * ]; + * ``` */ property entity oftype text; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv index a80444744..8b16dab89 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv @@ -1,37 +1,37 @@ -/* -Extracts a `File` from the web. - -@example Fetches a file from the given URL. -block CarsFileExtractor oftype HttpExtractor { - url: "tinyurl.com/4ub9spwz"; -} +/** +* Extracts a `File` from the web. +* +* @example Fetches a file from the given URL. +* block CarsFileExtractor oftype HttpExtractor { +* url: "tinyurl.com/4ub9spwz"; +* } */ builtin blocktype HttpExtractor { input default oftype None; output default oftype File; - /* - The URL to the file in the web to extract. + /** + * The URL to the file in the web to extract. */ property url oftype text; - /* - Configures how many retries should be executed after a failure fetching the data. + /** + * Configures how many retries should be executed after a failure fetching the data. */ property retries oftype integer: 0; - /* - Configures the wait time in milliseconds before executing a retry. + /** + * Configures the wait time in milliseconds before executing a retry. */ property retryBackoffMilliseconds oftype integer: 1000; - /* - Configures the wait strategy before executing a retry. Can have values "exponential" or "linear". + /** + * Configures the wait strategy before executing a retry. Can have values "exponential" or "linear". */ property retryBackoffStrategy oftype text: "exponential"; - /* - Indicates, whether to follow redirects on get requests. If `false`, redirects are not followed. Default `true` + /** + * Indicates, whether to follow redirects on get requests. If `false`, redirects are not followed. Default `true` */ property followRedirects oftype boolean: true; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv b/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv index cf3f86d79..c147bf0bb 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv @@ -1,47 +1,47 @@ -/* -Loads a `Table` into a PostgreSQL database sink. - -@example A local Postgres instance is filled with table data about cars. -block CarsLoader oftype PostgresLoader { - host: "localhost"; - port: 5432; - username: "postgres"; - password: "postgres"; - database: "CarsDB"; - table: "Cars"; -} +/** +* Loads a `Table` into a PostgreSQL database sink. +* +* @example A local Postgres instance is filled with table data about cars. +* block CarsLoader oftype PostgresLoader { +* host: "localhost"; +* port: 5432; +* username: "postgres"; +* password: "postgres"; +* database: "CarsDB"; +* table: "Cars"; +* } */ builtin blocktype PostgresLoader { input default oftype Table; output default oftype None; - /* - The hostname or IP address of the Postgres database. + /** + * The hostname or IP address of the Postgres database. */ property host oftype text; - /* - The port of the Postgres database. + /** + * The port of the Postgres database. */ property port oftype integer; - /* - The username to login to the Postgres database. + /** + * The username to login to the Postgres database. */ property username oftype text; - /* - The password to login to the Postgres database. + /** + * The password to login to the Postgres database. */ property password oftype text; - /* - The database to use. + /** + * The database to use. */ property database oftype text; - /* - The name of the table to write into. + /** + * The name of the table to write into. */ property table oftype text; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv index a12e92b56..8847e7604 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv @@ -1,17 +1,17 @@ -/* -Deletes one or more rows from a `Sheet`. Row IDs of subsequent rows will be shifted accordingly, so there will be no gaps. - -@example Deletes row 2 (i.e. the second row). -block SecondRowDeleter oftype RowDeleter { - delete: [row 2]; -} +/** +* Deletes one or more rows from a `Sheet`. Row IDs of subsequent rows will be shifted accordingly, so there will be no gaps. +* +* @example Deletes row 2 (i.e. the second row). +* block SecondRowDeleter oftype RowDeleter { +* delete: [row 2]; +* } */ builtin blocktype RowDeleter { input default oftype Sheet; output default oftype Sheet; - /* - The rows to delete. + /** + * The rows to delete. */ property delete oftype Collection; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv b/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv index 6edfd87c3..3883d4fac 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv @@ -1,17 +1,17 @@ -/* -Selects one `Sheet` from a `Workbook` based on its `sheetName`. If no sheet matches the name, no output is created and the execution of the pipeline is aborted. - -@example Tries to pick the sheet `AgencyNames` from the provided `Workbook`. If `AgencyNames` exists it is passed on as `Sheet`, if it does not exist the execution of the pipeline is aborted. -block AgencySheetPicker oftype SheetPicker { - sheetName: "AgencyNames"; -} +/** +* Selects one `Sheet` from a `Workbook` based on its `sheetName`. If no sheet matches the name, no output is created and the execution of the pipeline is aborted. +* +* @example Tries to pick the sheet `AgencyNames` from the provided `Workbook`. If `AgencyNames` exists it is passed on as `Sheet`, if it does not exist the execution of the pipeline is aborted. +* block AgencySheetPicker oftype SheetPicker { +* sheetName: "AgencyNames"; +* } */ builtin blocktype SheetPicker { input default oftype Workbook; output default oftype Sheet; - /* - The name of the sheet to select. + /** + * The name of the sheet to select. */ property sheetName oftype text; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv b/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv index 4a3d372a9..eb4a46934 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv @@ -1,28 +1,28 @@ -/* -Loads a `Table` into a SQLite database sink. - -@example A SQLite file `cars.db` is created in the working directory. Incoming data is written to the table `cars`. -block CarsLoader oftype SQLiteLoader { - table: "cars"; - file: "./cars.db"; -} +/** +* Loads a `Table` into a SQLite database sink. +* +* @example A SQLite file `cars.db` is created in the working directory. Incoming data is written to the table `cars`. +* block CarsLoader oftype SQLiteLoader { +* table: "cars"; +* file: "./cars.db"; +* } */ builtin blocktype SQLiteLoader { input default oftype Table; output default oftype None; - /* - The name of the table to write into. + /** + * The name of the table to write into. */ property table oftype text; - /* - The path to a SQLite file that will be created if it does not exist. Usual file extensions are `.sqlite` and `.db`. + /** + * The path to a SQLite file that will be created if it does not exist. Usual file extensions are `.sqlite` and `.db`. */ property file oftype text; - /* - Indicates, whether to drop the table before loading data into it. If `false`, data is appended to the table instead of dropping it. + /** + * Indicates, whether to drop the table before loading data into it. If `false`, data is appended to the table instead of dropping it. */ property dropTable oftype boolean: true; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv index 6669f6b1d..46a681006 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv @@ -1,37 +1,37 @@ -/* -Interprets a `Sheet` as a `Table`. In case a header row is present in the sheet, its names can be matched with the provided column names. Otherwise, the provided column names are assigned in order. - -@example Interprets a `Sheet` about cars with a topmost header row and interprets it as a `Table` by assigning a primitive valuetype to each column. The column names are matched to the header, so the order of the type assignments does not matter. -block CarsTableInterpreter oftype TableInterpreter { - header: true; - columns: [ - "name" oftype text, - "mpg" oftype decimal, - "cyl" oftype integer, - ]; -} - -@example Interprets a `Sheet` about cars without a topmost header row and interprets it as a `Table` by sequentially assigning a name and a primitive valuetype to each column of the sheet. Note that the order of columns matters here. The first column (column `A`) will be named "name", the second column (column `B`) will be named "mpg" etc. -block CarsTableInterpreter oftype TableInterpreter { - header: false; - columns: [ - "name" oftype text, - "mpg" oftype decimal, - "cyl" oftype integer, - ]; -} +/** +* Interprets a `Sheet` as a `Table`. In case a header row is present in the sheet, its names can be matched with the provided column names. Otherwise, the provided column names are assigned in order. +* +* @example Interprets a `Sheet` about cars with a topmost header row and interprets it as a `Table` by assigning a primitive valuetype to each column. The column names are matched to the header, so the order of the type assignments does not matter. +* block CarsTableInterpreter oftype TableInterpreter { +* header: true; +* columns: [ +* "name" oftype text, +* "mpg" oftype decimal, +* "cyl" oftype integer, +* ]; +* } +* +* @example Interprets a `Sheet` about cars without a topmost header row and interprets it as a `Table` by sequentially assigning a name and a primitive valuetype to each column of the sheet. Note that the order of columns matters here. The first column (column `A`) will be named "name", the second column (column `B`) will be named "mpg" etc. +* block CarsTableInterpreter oftype TableInterpreter { +* header: false; +* columns: [ +* "name" oftype text, +* "mpg" oftype decimal, +* "cyl" oftype integer, +* ]; +* } */ builtin blocktype TableInterpreter { input default oftype Sheet; output default oftype Table; - /* - Whether the first row should be interpreted as header row. + /** + * Whether the first row should be interpreted as header row. */ property header oftype boolean: true; - /* - Collection of valuetype assignments. Uses column names (potentially matched with the header or by sequence depending on the `header` property) to assign a primitive valuetype to each column. + /** + * Collection of valuetype assignments. Uses column names (potentially matched with the header or by sequence depending on the `header` property) to assign a primitive valuetype to each column. */ property columns oftype Collection; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv index c96bae02c..13383d111 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv @@ -1,52 +1,52 @@ -/* -Applies a transform on each value of a column. The input port type of the used transform has to match the type of the input column. - -@example Given a column "temperature" with temperature values in Celsius, it overwrites the column with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model. - -transform CelsiusToFahrenheit { - from Celsius oftype decimal; - to Fahrenheit oftype decimal; - - Fahrenheit: (Celsius * 9/5) + 32; -} - -block CelsiusToFahrenheitTransformer oftype TableTransformer { - inputColumns: ['temperature']; - outputColumn: 'temperature'; - use: CelsiusToFahrenheit; -} - -@example Given a column "temperatureCelsius" with temperature values in Celsius, it adds a new column "temperatureFahrenheit" with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model. - -transform CelsiusToFahrenheit { - from Celsius oftype decimal; - to Fahrenheit oftype decimal; - - Fahrenheit: (Celsius * 9/5) + 32; -} - -block CelsiusToFahrenheitTransformer oftype TableTransformer { - inputColumns: ['temperatureCelsius']; - outputColumn: 'temperatureFahrenheit'; - use: CelsiusToFahrenheit; -} +/** +* Applies a transform on each value of a column. The input port type of the used transform has to match the type of the input column. +* +* @example Given a column "temperature" with temperature values in Celsius, it overwrites the column with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model. +* +* transform CelsiusToFahrenheit { +* from Celsius oftype decimal; +* to Fahrenheit oftype decimal; +* +* Fahrenheit: (Celsius * 9/5) + 32; +* } +* +* block CelsiusToFahrenheitTransformer oftype TableTransformer { +* inputColumns: ['temperature']; +* outputColumn: 'temperature'; +* use: CelsiusToFahrenheit; +* } +* +* @example Given a column "temperatureCelsius" with temperature values in Celsius, it adds a new column "temperatureFahrenheit" with computed values in Fahrenheit by using the `CelsiusToFahrenheit` transform. The transform itself is defined elsewhere in the model. +* +* transform CelsiusToFahrenheit { +* from Celsius oftype decimal; +* to Fahrenheit oftype decimal; +* +* Fahrenheit: (Celsius * 9/5) + 32; +* } +* +* block CelsiusToFahrenheitTransformer oftype TableTransformer { +* inputColumns: ['temperatureCelsius']; +* outputColumn: 'temperatureFahrenheit'; +* use: CelsiusToFahrenheit; +* } */ builtin blocktype TableTransformer { input default oftype Table; output default oftype Table; - /* - The names of the input columns. The columns have to be present in the table and match with the transform's input port types. + /** + * The names of the input columns. The columns have to be present in the table and match with the transform's input port types. */ property inputColumns oftype Collection; - /* - The name of the output column. Overwrites the column if it already exists, or otherwise creates a new one. + /** + * The name of the output column. Overwrites the column if it already exists, or otherwise creates a new one. */ property outputColumn oftype text; - /* - Reference to the transform that is applied to the column. + /** + * Reference to the transform that is applied to the column. */ property use oftype Transform; } \ No newline at end of file diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv index fdfe50e06..63715b4ca 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv @@ -1,17 +1,17 @@ -/* -Interprets a `File` as a `TextFile`. +/** +* Interprets a `File` as a `TextFile`. */ builtin blocktype TextFileInterpreter { input default oftype File; output default oftype TextFile; - /* - The encoding used for decoding the file contents. + /** + * The encoding used for decoding the file contents. */ property encoding oftype text: 'utf-8'; - /* - The regex for identifying line breaks. + /** + * The regex for identifying line breaks. */ property lineBreak oftype Regex: /\r?\n/; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv index 8a6da0446..cf492433c 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv @@ -1,12 +1,12 @@ -/* -Deletes individual lines from a `TextFile`. +/** +* Deletes individual lines from a `TextFile`. */ builtin blocktype TextLineDeleter { input default oftype TextFile; output default oftype TextFile; - /* - The line numbers to delete. + /** + * The line numbers to delete. */ property lines oftype Collection; } diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv index 60291d72e..203152bf4 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv @@ -1,5 +1,5 @@ -/* -Selects a range of lines from a `TextFile`. +/** +* Selects a range of lines from a `TextFile`. */ builtin blocktype TextRangeSelector { input default oftype TextFile; diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv index c74e6ade6..1edbf5861 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv @@ -1,9 +1,8 @@ -/* -Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s. - -@example Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s. -block AgencyXLSXInterpreter oftype XLSXInterpreter { - } +/** +* Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s. +* +* @example Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s. +* block AgencyXLSXInterpreter oftype XLSXInterpreter { } */ builtin blocktype XLSXInterpreter { input default oftype File; From a21ccc6525cb7fd914682964ccc9bbf95bd74f6e Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 26 Sep 2023 14:29:54 +0200 Subject: [PATCH 35/43] Implement utility function getMetaInformation --- .../runtime-parameter-literal.ts | 17 +------- .../src/lib/ast/wrappers/util/index.ts | 42 +++++++++++++++++++ .../completion/jayvee-completion-provider.ts | 19 ++------- .../src/lib/hover/jayvee-hover-provider.ts | 23 ++-------- .../property-assignment.spec.ts | 13 +----- .../blocktype-specific/property-body.spec.ts | 14 +------ .../checks/property-assignment.spec.ts | 12 +----- .../lib/validation/checks/property-body.ts | 22 +--------- 8 files changed, 58 insertions(+), 104 deletions(-) diff --git a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts index 2fba3ddc4..c9108a597 100644 --- a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts +++ b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.ts @@ -3,17 +3,13 @@ // SPDX-License-Identifier: AGPL-3.0-only import { - BlockMetaInformation, BuiltinConstrainttypeDefinition, EvaluationContext, - MetaInformation, PropertyBody, ReferenceableBlocktypeDefinition, RuntimeParameterLiteral, ValidationContext, - getConstraintMetaInf, - isBuiltinConstrainttypeDefinition, - isReferenceableBlocktypeDefinition, + getMetaInformation, } from '@jvalue/jayvee-language-server'; import { Reference } from 'langium'; @@ -71,6 +67,7 @@ function checkRuntimeParameterValueParsing( | undefined = // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition enclosingPropertyBody.$container?.type; + const metaInf = getMetaInformation(type); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition const propertyName = runtimeParameter.$container?.name; @@ -79,16 +76,6 @@ function checkRuntimeParameterValueParsing( return; } - let metaInf: MetaInformation | undefined; - if ( - isReferenceableBlocktypeDefinition(type.ref) && - BlockMetaInformation.canBeWrapped(type.ref) - ) { - metaInf = new BlockMetaInformation(type.ref); - } else if (isBuiltinConstrainttypeDefinition(type.ref)) { - metaInf = getConstraintMetaInf(type.ref); - } - const propertySpec = metaInf?.getPropertySpecification(propertyName); if (propertySpec === undefined) { return; diff --git a/libs/language-server/src/lib/ast/wrappers/util/index.ts b/libs/language-server/src/lib/ast/wrappers/util/index.ts index b8983ed8e..27b5f1c22 100644 --- a/libs/language-server/src/lib/ast/wrappers/util/index.ts +++ b/libs/language-server/src/lib/ast/wrappers/util/index.ts @@ -2,4 +2,46 @@ // // SPDX-License-Identifier: AGPL-3.0-only +import { Reference, assertUnreachable, isReference } from 'langium'; + +// eslint-disable-next-line import/no-cycle +import { + BlockMetaInformation, + ConstraintMetaInformation, + getConstraintMetaInf, +} from '../../../meta-information'; +import { + BuiltinConstrainttypeDefinition, + ReferenceableBlocktypeDefinition, + isBuiltinConstrainttypeDefinition, + isReferenceableBlocktypeDefinition, +} from '../../generated/ast'; + export * from './column-id-util'; + +/** + * Creates a MetaInformation wrapper object based on the given type reference. + */ +export function getMetaInformation( + typeRef: + | Reference + | Reference + | BuiltinConstrainttypeDefinition + | ReferenceableBlocktypeDefinition + | undefined, +): BlockMetaInformation | ConstraintMetaInformation | undefined { + const type = isReference(typeRef) ? typeRef.ref : typeRef; + if (type === undefined) { + return undefined; + } + + if (isReferenceableBlocktypeDefinition(type)) { + if (!BlockMetaInformation.canBeWrapped(type)) { + return undefined; + } + return new BlockMetaInformation(type); + } else if (isBuiltinConstrainttypeDefinition(type)) { + return getConstraintMetaInf(type); + } + assertUnreachable(type); +} diff --git a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts index 1d3be1893..b590d641b 100644 --- a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts +++ b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts @@ -16,7 +16,7 @@ import { } from 'langium'; import { CompletionItemKind } from 'vscode-languageserver'; -import { createValuetype } from '../ast'; +import { createValuetype, getMetaInformation } from '../ast'; import { BlockDefinition, ConstraintDefinition, @@ -24,20 +24,15 @@ import { PropertyBody, ValuetypeReference, isBlockDefinition, - isBuiltinConstrainttypeDefinition, isConstraintDefinition, isJayveeModel, isPropertyAssignment, isPropertyBody, - isReferenceableBlocktypeDefinition, } from '../ast/generated/ast'; import { LspDocGenerator } from '../docs/lsp-doc-generator'; import { BlockMetaInformation } from '../meta-information'; import { MetaInformation } from '../meta-information/meta-inf'; -import { - getConstraintMetaInf, - getRegisteredConstraintMetaInformation, -} from '../meta-information/meta-inf-registry'; +import { getRegisteredConstraintMetaInformation } from '../meta-information/meta-inf-registry'; const RIGHT_ARROW_SYMBOL = '\u{2192}'; @@ -165,15 +160,7 @@ export class JayveeCompletionProvider extends DefaultCompletionProvider { container = astNode.$container.$container; } - let metaInf: MetaInformation | undefined; - if (isReferenceableBlocktypeDefinition(container.type.ref)) { - if (!BlockMetaInformation.canBeWrapped(container.type.ref)) { - return; - } - metaInf = new BlockMetaInformation(container.type.ref); - } else if (isBuiltinConstrainttypeDefinition(container.type.ref)) { - metaInf = getConstraintMetaInf(container.type.ref); - } + const metaInf = getMetaInformation(container.type); if (metaInf === undefined) { return; } diff --git a/libs/language-server/src/lib/hover/jayvee-hover-provider.ts b/libs/language-server/src/lib/hover/jayvee-hover-provider.ts index cb6e83582..d29eba901 100644 --- a/libs/language-server/src/lib/hover/jayvee-hover-provider.ts +++ b/libs/language-server/src/lib/hover/jayvee-hover-provider.ts @@ -2,28 +2,21 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { - AstNode, - AstNodeHoverProvider, - MaybePromise, - assertUnreachable, -} from 'langium'; +import { AstNode, AstNodeHoverProvider, MaybePromise } from 'langium'; import { Hover } from 'vscode-languageserver-protocol'; import { BuiltinBlocktypeDefinition, BuiltinConstrainttypeDefinition, PropertyAssignment, - isBlockDefinition, + getMetaInformation, isBuiltinBlocktypeDefinition, isBuiltinConstrainttypeDefinition, isPropertyAssignment, - isTypedConstraintDefinition, } from '../ast'; import { LspDocGenerator } from '../docs/lsp-doc-generator'; import { BlockMetaInformation, - MetaInformation, getConstraintMetaInf, } from '../meta-information'; @@ -82,17 +75,7 @@ export class JayveeHoverProvider extends AstNodeHoverProvider { property: PropertyAssignment, ): string | undefined { const container = property.$container.$container; - let metaInf: MetaInformation | undefined; - if (isTypedConstraintDefinition(container)) { - metaInf = getConstraintMetaInf(container.type); - } else if (isBlockDefinition(container)) { - if (!BlockMetaInformation.canBeWrapped(container.type)) { - return; - } - metaInf = new BlockMetaInformation(container.type); - } else { - assertUnreachable(container); - } + const metaInf = getMetaInformation(container.type); if (metaInf === undefined) { return; } diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.spec.ts index 0c1dd2098..81ab7e95f 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.spec.ts @@ -6,7 +6,6 @@ import { AstNode, AstNodeLocator, LangiumDocument } from 'langium'; import { NodeFileSystem } from 'langium/node'; import { - BlockMetaInformation, EvaluationContext, MetaInformation, PropertyBody, @@ -14,9 +13,7 @@ import { RuntimeParameterProvider, ValidationContext, createJayveeServices, - getConstraintMetaInf, - isBuiltinConstrainttypeDefinition, - isReferenceableBlocktypeDefinition, + getMetaInformation, } from '../../..'; import { ParseHelperOptions, @@ -52,13 +49,7 @@ describe('Validation of blocktype specific properties', () => { 'pipelines@0/blocks@0/body', ) as PropertyBody; - const type = propertyBody.$container.type; - let metaInf: MetaInformation | undefined; - if (isReferenceableBlocktypeDefinition(type.ref)) { - metaInf = new BlockMetaInformation(type.ref); - } else if (isBuiltinConstrainttypeDefinition(type.ref)) { - metaInf = getConstraintMetaInf(type.ref); - } + const metaInf = getMetaInformation(propertyBody.$container.type); expect(metaInf).toBeDefined(); propertyBody.properties.forEach((propertyAssignment) => { diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts index 0078b24a8..16757140d 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.spec.ts @@ -6,16 +6,12 @@ import { AstNode, AstNodeLocator, LangiumDocument } from 'langium'; import { NodeFileSystem } from 'langium/node'; import { - BlockMetaInformation, EvaluationContext, - MetaInformation, PropertyBody, RuntimeParameterProvider, ValidationContext, createJayveeServices, - getConstraintMetaInf, - isBuiltinConstrainttypeDefinition, - isReferenceableBlocktypeDefinition, + getMetaInformation, } from '../../..'; import { ParseHelperOptions, @@ -51,13 +47,7 @@ describe('Validation of blocktype specific property bodies', () => { 'pipelines@0/blocks@0/body', ) as PropertyBody; - const type = propertyBody.$container.type; - let metaInf: MetaInformation | undefined; - if (isReferenceableBlocktypeDefinition(type.ref)) { - metaInf = new BlockMetaInformation(type.ref); - } else if (isBuiltinConstrainttypeDefinition(type.ref)) { - metaInf = getConstraintMetaInf(type.ref); - } + const metaInf = getMetaInformation(propertyBody.$container.type); expect(metaInf).toBeDefined(); checkBlocktypeSpecificPropertyBody( diff --git a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts index fe4079c55..205354455 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.spec.ts @@ -6,7 +6,6 @@ import { AstNode, AstNodeLocator, LangiumDocument } from 'langium'; import { NodeFileSystem } from 'langium/node'; import { - BlockMetaInformation, EvaluationContext, MetaInformation, PropertyAssignment, @@ -14,9 +13,7 @@ import { RuntimeParameterProvider, ValidationContext, createJayveeServices, - getConstraintMetaInf, - isBuiltinConstrainttypeDefinition, - isReferenceableBlocktypeDefinition, + getMetaInformation, } from '../../../lib'; import { ParseHelperOptions, @@ -53,12 +50,7 @@ describe('Validation of PropertyAssignment', () => { ) as PropertyBody; const type = propertyBody.$container.type; - let metaInf: MetaInformation | undefined; - if (isReferenceableBlocktypeDefinition(type.ref)) { - metaInf = new BlockMetaInformation(type.ref); - } else if (isBuiltinConstrainttypeDefinition(type.ref)) { - metaInf = getConstraintMetaInf(type.ref); - } + const metaInf = getMetaInformation(type); expect(metaInf).toBeDefined(); const propertyAssignment = locator.getAstNode( diff --git a/libs/language-server/src/lib/validation/checks/property-body.ts b/libs/language-server/src/lib/validation/checks/property-body.ts index 14228a616..48015b3c7 100644 --- a/libs/language-server/src/lib/validation/checks/property-body.ts +++ b/libs/language-server/src/lib/validation/checks/property-body.ts @@ -7,19 +7,14 @@ */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ -import { assertUnreachable } from 'langium'; - +import { getMetaInformation } from '../../ast'; import { EvaluationContext } from '../../ast/expressions/evaluation'; import { PropertyAssignment, PropertyBody, isBlockDefinition, - isBuiltinConstrainttypeDefinition, - isReferenceableBlocktypeDefinition, } from '../../ast/generated/ast'; -import { BlockMetaInformation } from '../../meta-information/block-meta-inf'; import { MetaInformation } from '../../meta-information/meta-inf'; -import { getConstraintMetaInf } from '../../meta-information/meta-inf-registry'; import { ValidationContext } from '../validation-context'; import { checkUniqueNames } from '../validation-util'; @@ -69,20 +64,7 @@ function inferMetaInformation( propertyBody: PropertyBody, ): MetaInformation | undefined { const type = propertyBody.$container?.type.ref; - if (type === undefined) { - return undefined; - } - - if (isBuiltinConstrainttypeDefinition(type)) { - return getConstraintMetaInf(type); - } else if (isReferenceableBlocktypeDefinition(type)) { - if (!BlockMetaInformation.canBeWrapped(type)) { - return; - } - return new BlockMetaInformation(type); - } - - assertUnreachable(type); + return getMetaInformation(type); } function checkPropertyCompleteness( From 8d7bc1aa5e80c0d75bafc4b9fa8868e59de008eb Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 26 Sep 2023 14:30:46 +0200 Subject: [PATCH 36/43] Remove JayveeDocumentationProvider --- .../lib/services/jayvee-documentation-provider.ts | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 libs/language-server/src/lib/services/jayvee-documentation-provider.ts diff --git a/libs/language-server/src/lib/services/jayvee-documentation-provider.ts b/libs/language-server/src/lib/services/jayvee-documentation-provider.ts deleted file mode 100644 index a2ce03c31..000000000 --- a/libs/language-server/src/lib/services/jayvee-documentation-provider.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { AstNode, findCommentNode } from 'langium'; -import { JSDocDocumentationProvider } from 'langium/lib/documentation/documentation-provider'; - -export class JayveeDocumentationProvider extends JSDocDocumentationProvider { - override getDocumentation(node: AstNode): string | undefined { - const lastNode = findCommentNode( - node.$cstNode, - this.grammarConfig.multilineCommentRules, - ); - if (lastNode === undefined) { - return; - } - return lastNode.text.replace('/*', '').replace('*/', ''); - } -} From 7932bd99c9e7225eb5fbad6930bb83a9de7c293e Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 26 Sep 2023 14:33:35 +0200 Subject: [PATCH 37/43] Fix linter and test --- libs/language-server/src/lib/ast/wrappers/index.ts | 1 + .../src/lib/validation/checks/property-body.spec.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/language-server/src/lib/ast/wrappers/index.ts b/libs/language-server/src/lib/ast/wrappers/index.ts index 1f0f2322d..1abdeaba0 100644 --- a/libs/language-server/src/lib/ast/wrappers/index.ts +++ b/libs/language-server/src/lib/ast/wrappers/index.ts @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only +// eslint-disable-next-line import/no-cycle export * from './util'; // eslint-disable-next-line import/no-cycle export * from './value-type'; diff --git a/libs/language-server/src/lib/validation/checks/property-body.spec.ts b/libs/language-server/src/lib/validation/checks/property-body.spec.ts index 6a81c38de..343c53cbf 100644 --- a/libs/language-server/src/lib/validation/checks/property-body.spec.ts +++ b/libs/language-server/src/lib/validation/checks/property-body.spec.ts @@ -97,7 +97,7 @@ describe('Validation PropertyBody', () => { expect(validationAcceptorMock).toHaveBeenCalledTimes(1); expect(validationAcceptorMock).toHaveBeenCalledWith( 'error', - 'The value needs to be of type CustomValuetype but is of type text', + 'The value of property "customValidationTextProperty" needs to be of type CustomValuetype but is of type text', expect.any(Object), ); }); From 4cd0a787c81e5c26609d85f2f703dde6b8977d61 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 26 Sep 2023 15:05:31 +0200 Subject: [PATCH 38/43] Pull out function getAllBuiltinBlocktypes --- apps/docs/generator/src/main.ts | 21 ++------- .../interpreter-lib/src/std-extension.spec.ts | 29 ++---------- .../language-server/src/lib/ast/model-util.ts | 38 +++++++++++++++- .../completion/jayvee-completion-provider.ts | 44 +++++++------------ 4 files changed, 62 insertions(+), 70 deletions(-) diff --git a/apps/docs/generator/src/main.ts b/apps/docs/generator/src/main.ts index 69b614e31..156dbcbb5 100644 --- a/apps/docs/generator/src/main.ts +++ b/apps/docs/generator/src/main.ts @@ -6,13 +6,12 @@ import { readFileSync, readdirSync, writeFileSync } from 'fs'; import { join } from 'path'; import { - BlockMetaInformation, JayveeServices, PrimitiveValuetypes, createJayveeServices, + getAllBuiltinBlocktypes, getRegisteredConstraintMetaInformation, initializeWorkspace, - isJayveeModel, } from '@jvalue/jayvee-language-server'; import { NodeFileSystem } from 'langium/node'; @@ -34,21 +33,9 @@ function generateBlockTypeDocs( services: JayveeServices, rootPath: string, ): void { - const documentService = services.shared.workspace.LangiumDocuments; - - const metaInfs: BlockMetaInformation[] = []; - documentService.all - .map((document) => document.parseResult.value) - .forEach((parsedDocument) => { - if (!isJayveeModel(parsedDocument)) { - throw new Error('Expected parsed document to be a JayveeModel'); - } - parsedDocument.blocktypes.forEach((blocktypeDefinition) => { - if (BlockMetaInformation.canBeWrapped(blocktypeDefinition)) { - metaInfs.push(new BlockMetaInformation(blocktypeDefinition)); - } - }); - }); + const metaInfs = getAllBuiltinBlocktypes( + services.shared.workspace.LangiumDocuments, + ); const docsPath = join( rootPath, diff --git a/libs/interpreter-lib/src/std-extension.spec.ts b/libs/interpreter-lib/src/std-extension.spec.ts index 2fe2046dc..8fcd37917 100644 --- a/libs/interpreter-lib/src/std-extension.spec.ts +++ b/libs/interpreter-lib/src/std-extension.spec.ts @@ -8,44 +8,23 @@ import { getRegisteredBlockExecutors } from '@jvalue/jayvee-execution'; import { BlockMetaInformation, createJayveeServices, + getAllBuiltinBlocktypes, initializeWorkspace, - isBuiltinBlocktypeDefinition, - isJayveeModel, } from '@jvalue/jayvee-language-server'; import { NodeFileSystem } from 'langium/node'; import { useStdExtension } from './interpreter'; -async function getAllBuiltinBlocktypes(): Promise { - const allBuiltinBlocktypes: BlockMetaInformation[] = []; +async function loadAllBuiltinBlocktypes(): Promise { const services = createJayveeServices(NodeFileSystem).Jayvee; await initializeWorkspace(services); - const documentService = services.shared.workspace.LangiumDocuments; - - documentService.all - .map((document) => document.parseResult.value) - .forEach((parsedDocument) => { - if (!isJayveeModel(parsedDocument)) { - throw new Error('Expected parsed document to be a JayveeModel'); - } - parsedDocument.blocktypes.forEach((blocktypeDefinition) => { - if (!isBuiltinBlocktypeDefinition(blocktypeDefinition)) { - return; - } - if (BlockMetaInformation.canBeWrapped(blocktypeDefinition)) { - allBuiltinBlocktypes.push( - new BlockMetaInformation(blocktypeDefinition), - ); - } - }); - }); - return allBuiltinBlocktypes; + return getAllBuiltinBlocktypes(services.shared.workspace.LangiumDocuments); } describe('std extension', () => { it('should provide matching block executors for builtin block types', async () => { useStdExtension(); - (await getAllBuiltinBlocktypes()).forEach( + (await loadAllBuiltinBlocktypes()).forEach( (metaInf: BlockMetaInformation) => { console.info(`Looking for executor for blocktype ${metaInf.type}`); const matchingBlockExecutorClass = getRegisteredBlockExecutors().find( diff --git a/libs/language-server/src/lib/ast/model-util.ts b/libs/language-server/src/lib/ast/model-util.ts index f525044d8..6fed4ed32 100644 --- a/libs/language-server/src/lib/ast/model-util.ts +++ b/libs/language-server/src/lib/ast/model-util.ts @@ -4,7 +4,12 @@ import { strict as assert } from 'assert'; -import { AstNode, Reference, assertUnreachable } from 'langium'; +import { + AstNode, + LangiumDocuments, + Reference, + assertUnreachable, +} from 'langium'; // eslint-disable-next-line import/no-cycle import { BlockMetaInformation } from '../meta-information'; @@ -15,7 +20,9 @@ import { CompositeBlocktypeDefinition, PipelineDefinition, UnaryExpression, + isBuiltinBlocktypeDefinition, isCompositeBlocktypeDefinition, + isJayveeModel, } from './generated/ast'; import { PipeWrapper, createSemanticPipes } from './wrappers/pipe-wrapper'; @@ -187,3 +194,32 @@ export function getNextAstNodeContainer( } return getNextAstNodeContainer(node.$container, guard); } + +/** + * Utility function that gets all builtin blocktypes. + * Make sure to call @see initializeWorkspace first so that the file system is initialized. + */ +export function getAllBuiltinBlocktypes( + documentService: LangiumDocuments, +): BlockMetaInformation[] { + const allBuiltinBlocktypes: BlockMetaInformation[] = []; + + documentService.all + .map((document) => document.parseResult.value) + .forEach((parsedDocument) => { + if (!isJayveeModel(parsedDocument)) { + throw new Error('Expected parsed document to be a JayveeModel'); + } + parsedDocument.blocktypes.forEach((blocktypeDefinition) => { + if (!isBuiltinBlocktypeDefinition(blocktypeDefinition)) { + return; + } + if (BlockMetaInformation.canBeWrapped(blocktypeDefinition)) { + allBuiltinBlocktypes.push( + new BlockMetaInformation(blocktypeDefinition), + ); + } + }); + }); + return allBuiltinBlocktypes; +} diff --git a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts index b590d641b..3574d2896 100644 --- a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts +++ b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts @@ -29,8 +29,8 @@ import { isPropertyAssignment, isPropertyBody, } from '../ast/generated/ast'; +import { getAllBuiltinBlocktypes } from '../ast/model-util'; import { LspDocGenerator } from '../docs/lsp-doc-generator'; -import { BlockMetaInformation } from '../meta-information'; import { MetaInformation } from '../meta-information/meta-inf'; import { getRegisteredConstraintMetaInformation } from '../meta-information/meta-inf-registry'; @@ -82,33 +82,23 @@ export class JayveeCompletionProvider extends DefaultCompletionProvider { private completionForBlockType( acceptor: CompletionAcceptor, ): MaybePromise { - this.langiumDocumentService.all - .map((document) => document.parseResult.value) - .forEach((parsedDocument) => { - if (!isJayveeModel(parsedDocument)) { - throw new Error('Expected parsed document to be a JayveeModel'); - } - parsedDocument.blocktypes.forEach((blocktypeDefinition) => { - if (!BlockMetaInformation.canBeWrapped(blocktypeDefinition)) { - return; - } - const blocktype = new BlockMetaInformation(blocktypeDefinition); - const lspDocBuilder = new LspDocGenerator(); - const markdownDoc = lspDocBuilder.generateBlockTypeDoc(blocktype); - acceptor({ - label: blocktype.type, - labelDetails: { - detail: ` ${blocktype.inputType} ${RIGHT_ARROW_SYMBOL} ${blocktype.outputType}`, - }, - kind: CompletionItemKind.Class, - detail: `(block type)`, - documentation: { - kind: 'markdown', - value: markdownDoc, - }, - }); - }); + const blockMetaInfs = getAllBuiltinBlocktypes(this.langiumDocumentService); + blockMetaInfs.forEach((blocktype) => { + const lspDocBuilder = new LspDocGenerator(); + const markdownDoc = lspDocBuilder.generateBlockTypeDoc(blocktype); + acceptor({ + label: blocktype.type, + labelDetails: { + detail: ` ${blocktype.inputType} ${RIGHT_ARROW_SYMBOL} ${blocktype.outputType}`, + }, + kind: CompletionItemKind.Class, + detail: `(block type)`, + documentation: { + kind: 'markdown', + value: markdownDoc, + }, }); + }); } private completionForConstraintType( From 2e64c2263e53d9212935bdd85ed62d7beb80c146 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 26 Sep 2023 15:26:19 +0200 Subject: [PATCH 39/43] Update docs --- .../dev/04-guides/06-jayvee-extensions.md | 139 ++++-------------- 1 file changed, 27 insertions(+), 112 deletions(-) diff --git a/apps/docs/docs/dev/04-guides/06-jayvee-extensions.md b/apps/docs/docs/dev/04-guides/06-jayvee-extensions.md index 11c34e02c..51c9074d1 100644 --- a/apps/docs/docs/dev/04-guides/06-jayvee-extensions.md +++ b/apps/docs/docs/dev/04-guides/06-jayvee-extensions.md @@ -13,55 +13,44 @@ Jayvee extensions that shall be used by default are bundled into the so-called [ ### Language extension +:::info +This mechanism is currently under construction! We are moving from a code-first approach (using typescript classes to generate the Jayvee model of the blocktype) to a model-first approach (parsing the Jayvee model of the blocktype and creating ast wrappers). +::: + 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//lang" npx nx g @nrwl/node:library --name="extensions//exec" ``` #### 2. Create extension classes -In `libs/extensions//lang/src/extension.ts`: - -```typescript -import { - BlockMetaInformation, - ConstructorClass, - JayveeLangExtension, -} from '@jvalue/jayvee-language-server'; - -export class MyLangExtension implements JayveeLangExtension { - getBlockMetaInf(): Array> { - return []; - } -} - -``` - In `libs/extensions//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[] { @@ -72,12 +61,6 @@ export class MyExecExtension implements JayveeExecExtension { #### 3. Export extension classes -In `libs/extensions//lang/src/index.ts`: - -```typescript -export * from './extension'; -``` - In `libs/extensions//exec/src/index.ts`: ```typescript @@ -86,25 +69,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//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 @@ -126,77 +90,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//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//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> { - return [ - // ... - // Register your meta information here: - MyExtractorMetaInformation, - // ... - ]; - } -} -``` #### 3. Implement `BlockExecutor` @@ -223,7 +138,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; @@ -240,7 +155,7 @@ export class MyExtractorExecutor 'limit', PrimitiveValuetypes.Integer, ); - + // ... if (error) { From e3caa48d217883c6b43aa11178ca758cfe15af49 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Tue, 26 Sep 2023 15:29:03 +0200 Subject: [PATCH 40/43] Add missing license headers --- .../checks/blocktype-specific/property-assignment.ts | 4 ++++ .../lib/validation/checks/blocktype-specific/property-body.ts | 4 ++++ .../src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/CellRangeSelector.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/CellWriter.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/ColumnDeleter.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/CsvInterpreter.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/FilePicker.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/HttpExtractor.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/PostgresLoader.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/RowDeleter.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/SheetPicker.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/SqliteLoader.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/TableInterpreter.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/TableTransformer.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/TextFileInterpreter.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/TextLineDeleter.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/TextRangeSelector.jv | 4 ++++ .../src/stdlib/builtin-blocktypes/XlsInterpreter.jv | 4 ++++ 20 files changed, 80 insertions(+) diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.ts index 1ad47a6f8..9f91c252d 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-assignment.ts @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + import { CollectionValuetype, EvaluationContext, diff --git a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts index bff57b615..530488256 100644 --- a/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts +++ b/libs/language-server/src/lib/validation/checks/blocktype-specific/property-body.ts @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + import { CollectionValuetype, EvaluationContext, diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv index 21ea227ce..d490c5a76 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/ArchiveInterpreter.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Interprets a `File` as an archive file and converts it to a `FileSystem`. The archive file root is considered the root of the `FileSystem`. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv index b725f8c1a..87182fa4c 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CellRangeSelector.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Selects a subset of a `Sheet` to produce a new `Sheet`. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv index 8d4407554..6ff64a4e1 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CellWriter.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Writes textual values into cells of a `Sheet`. The number of text values needs to match the number of cells to write into. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv index d3f15f5e7..1c3f18ec6 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/ColumnDeleter.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Deletes columns from a `Sheet`. Column IDs of subsequent columns will be shifted accordingly, so there will be no gaps. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv index 3c4fb3d61..fb654e4c3 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/CsvInterpreter.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Interprets an input file as a csv-file containing string-values delimited by `delimiter` and outputs a `Sheet`. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv b/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv index cd4d8ca25..0b0cb8093 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/FilePicker.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Selects one `File` from a `FileSystem` based on its relative path to the root of the `FileSystem`. If no file matches the relative path, no output is created and the execution of the pipeline is aborted. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv index f77cd71a7..9caf39017 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/GtfsRtInterpreter.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Interprets an protobuf file (binary) of type `File` by decoding the file according to `gtfs-realtime.proto`. Outputs the extracted entity defined by `entity` as a `Sheet` * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv index 8b16dab89..014328c96 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/HttpExtractor.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Extracts a `File` from the web. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv b/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv index c147bf0bb..2b2a824ab 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/PostgresLoader.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Loads a `Table` into a PostgreSQL database sink. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv index 8847e7604..9835a2326 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/RowDeleter.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Deletes one or more rows from a `Sheet`. Row IDs of subsequent rows will be shifted accordingly, so there will be no gaps. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv b/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv index 3883d4fac..e9591c888 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/SheetPicker.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Selects one `Sheet` from a `Workbook` based on its `sheetName`. If no sheet matches the name, no output is created and the execution of the pipeline is aborted. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv b/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv index eb4a46934..3a69197e1 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/SqliteLoader.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Loads a `Table` into a SQLite database sink. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv index 46a681006..8efb5e892 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TableInterpreter.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Interprets a `Sheet` as a `Table`. In case a header row is present in the sheet, its names can be matched with the provided column names. Otherwise, the provided column names are assigned in order. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv index 13383d111..6a022ffb9 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TableTransformer.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Applies a transform on each value of a column. The input port type of the used transform has to match the type of the input column. * diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv index 63715b4ca..32e1a46c7 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextFileInterpreter.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Interprets a `File` as a `TextFile`. */ diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv index cf492433c..226996221 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextLineDeleter.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Deletes individual lines from a `TextFile`. */ diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv b/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv index 203152bf4..58f6b8508 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/TextRangeSelector.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Selects a range of lines from a `TextFile`. */ diff --git a/libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv b/libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv index 1edbf5861..40c3fcfcc 100644 --- a/libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv +++ b/libs/language-server/src/stdlib/builtin-blocktypes/XlsInterpreter.jv @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + /** * Interprets an input file as a XLSX-file and outputs a `Workbook` containing `Sheet`s. * From 48b883c15d6416e5e6006d7e6cff186f6decb8d9 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 2 Nov 2023 15:10:41 +0100 Subject: [PATCH 41/43] Remove info box from docs --- apps/docs/docs/dev/04-guides/06-jayvee-extensions.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/docs/docs/dev/04-guides/06-jayvee-extensions.md b/apps/docs/docs/dev/04-guides/06-jayvee-extensions.md index 51c9074d1..e62532637 100644 --- a/apps/docs/docs/dev/04-guides/06-jayvee-extensions.md +++ b/apps/docs/docs/dev/04-guides/06-jayvee-extensions.md @@ -13,10 +13,6 @@ Jayvee extensions that shall be used by default are bundled into the so-called [ ### Language extension -:::info -This mechanism is currently under construction! We are moving from a code-first approach (using typescript classes to generate the Jayvee model of the blocktype) to a model-first approach (parsing the Jayvee model of the blocktype and creating ast wrappers). -::: - 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 From 7d98ae4f02dafb0e4f342236e3708f8c0114095c Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 2 Nov 2023 15:15:11 +0100 Subject: [PATCH 42/43] Ignore duplicates in getAllBuiltinBlocktypes --- libs/language-server/src/lib/ast/model-util.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libs/language-server/src/lib/ast/model-util.ts b/libs/language-server/src/lib/ast/model-util.ts index 6fed4ed32..dc93fb930 100644 --- a/libs/language-server/src/lib/ast/model-util.ts +++ b/libs/language-server/src/lib/ast/model-util.ts @@ -17,6 +17,7 @@ import { BlockMetaInformation } from '../meta-information'; import { BinaryExpression, BlockDefinition, + BuiltinBlocktypeDefinition, CompositeBlocktypeDefinition, PipelineDefinition, UnaryExpression, @@ -197,12 +198,15 @@ export function getNextAstNodeContainer( /** * Utility function that gets all builtin blocktypes. + * Duplicates are only added once. * Make sure to call @see initializeWorkspace first so that the file system is initialized. */ export function getAllBuiltinBlocktypes( documentService: LangiumDocuments, ): BlockMetaInformation[] { const allBuiltinBlocktypes: BlockMetaInformation[] = []; + const visitedBuiltinBlocktypeDefinitions = + new Set(); documentService.all .map((document) => document.parseResult.value) @@ -214,10 +218,18 @@ export function getAllBuiltinBlocktypes( if (!isBuiltinBlocktypeDefinition(blocktypeDefinition)) { return; } + + const wasAlreadyVisited = + visitedBuiltinBlocktypeDefinitions.has(blocktypeDefinition); + if (wasAlreadyVisited) { + return; + } + if (BlockMetaInformation.canBeWrapped(blocktypeDefinition)) { allBuiltinBlocktypes.push( new BlockMetaInformation(blocktypeDefinition), ); + visitedBuiltinBlocktypeDefinitions.add(blocktypeDefinition); } }); }); From 57ee14df74b536f0a75c4c482672e80c9028d6e4 Mon Sep 17 00:00:00 2001 From: Georg Schwarz Date: Thu, 2 Nov 2023 16:00:43 +0100 Subject: [PATCH 43/43] Adapt tests to changes --- libs/interpreter-lib/src/parsing-util.spec.ts | 15 ++++++++++----- .../runtime-parameter-literal.spec.ts | 15 ++++++++++----- .../test-extension/TestBlockTypes.jv | 18 ++++++++++++++++++ .../jayvee-workspace-manager.ts | 2 +- 4 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 libs/interpreter-lib/test/assets/parsing-util/test-extension/TestBlockTypes.jv diff --git a/libs/interpreter-lib/src/parsing-util.spec.ts b/libs/interpreter-lib/src/parsing-util.spec.ts index 58e7dcf68..cd5de83db 100644 --- a/libs/interpreter-lib/src/parsing-util.spec.ts +++ b/libs/interpreter-lib/src/parsing-util.spec.ts @@ -8,11 +8,10 @@ import { CachedLogger } from '@jvalue/jayvee-execution'; import { JayveeServices, createJayveeServices, - useExtension, + initializeWorkspace, } from '@jvalue/jayvee-language-server'; import { ParseHelperOptions, - TestLangExtension, expectNoParserAndLexerErrors, parseHelper, readJvTestAssetHelper, @@ -39,7 +38,7 @@ describe('Validation of parsing-util', () => { '../test/assets/parsing-util/', ); - beforeAll(() => { + beforeAll(async () => { // Mock Process.exit exitSpy = jest .spyOn(process, 'exit') @@ -50,10 +49,16 @@ describe('Validation of parsing-util', () => { throw new Error(`process.exit: ${code}`); }); - // Register test extension - useExtension(new TestLangExtension()); // Create language services services = createJayveeServices(NodeFileSystem).Jayvee; + + await initializeWorkspace(services, [ + { + uri: process.cwd(), + name: 'TestBlockTypes.jv', + }, + ]); + // Parse function for Jayvee (without validation) parse = parseHelper(services); }); diff --git a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.spec.ts b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.spec.ts index 3475001a1..2e392e10f 100644 --- a/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.spec.ts +++ b/libs/interpreter-lib/src/validation-checks/runtime-parameter-literal.spec.ts @@ -9,11 +9,10 @@ import { RuntimeParameterProvider, ValidationContext, createJayveeServices, - useExtension, + initializeWorkspace, } from '@jvalue/jayvee-language-server'; import { ParseHelperOptions, - TestLangExtension, expectNoParserAndLexerErrors, parseHelper, readJvTestAssetHelper, @@ -66,12 +65,18 @@ describe('Validation of validateRuntimeParameterLiteral', () => { ); } - beforeAll(() => { - // Register test extension - useExtension(new TestLangExtension()); + beforeAll(async () => { // Create language services const services = createJayveeServices(NodeFileSystem).Jayvee; + + await initializeWorkspace(services, [ + { + uri: process.cwd(), + name: 'TestBlockTypes.jv', + }, + ]); locator = services.workspace.AstNodeLocator; + // Parse function for Jayvee (without validation) parse = parseHelper(services); }); diff --git a/libs/interpreter-lib/test/assets/parsing-util/test-extension/TestBlockTypes.jv b/libs/interpreter-lib/test/assets/parsing-util/test-extension/TestBlockTypes.jv new file mode 100644 index 000000000..bf5bb4357 --- /dev/null +++ b/libs/interpreter-lib/test/assets/parsing-util/test-extension/TestBlockTypes.jv @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +builtin blocktype TestFileExtractor { + input inPort oftype None; + output outPort oftype File; +} + +builtin blocktype TestFileLoader { + input inPort oftype File; + output outPort oftype None; +} + +builtin blocktype TestTableLoader { + input inPort oftype Table; + output outPort oftype None; +} diff --git a/libs/language-server/src/lib/builtin-library/jayvee-workspace-manager.ts b/libs/language-server/src/lib/builtin-library/jayvee-workspace-manager.ts index 88f43e3a3..5c93277c7 100644 --- a/libs/language-server/src/lib/builtin-library/jayvee-workspace-manager.ts +++ b/libs/language-server/src/lib/builtin-library/jayvee-workspace-manager.ts @@ -40,8 +40,8 @@ export class JayveeWorkspaceManager extends DefaultWorkspaceManager { */ export async function initializeWorkspace( services: LangiumServices, + workspaceFolders: WorkspaceFolder[] = [], ): Promise { - const workspaceFolders: WorkspaceFolder[] = []; await services.shared.workspace.WorkspaceManager.initializeWorkspace( workspaceFolders, );