diff --git a/apps/docs/generator/src/main.ts b/apps/docs/generator/src/main.ts index 28eeb58c..b93afc3d 100644 --- a/apps/docs/generator/src/main.ts +++ b/apps/docs/generator/src/main.ts @@ -7,7 +7,6 @@ import { join } from 'path'; import { type JayveeServices, - PrimitiveValuetypes, createJayveeServices, getAllBuiltinBlockTypes, getAllBuiltinConstraintTypes, @@ -102,8 +101,9 @@ function generateValueTypeDocs( 'value-types', ); const userDocBuilder = new UserDocGenerator(services); - const valueTypeDoc = - userDocBuilder.generateValueTypesDoc(PrimitiveValuetypes); + const valueTypeDoc = userDocBuilder.generateValueTypesDoc( + services.ValueTypeProvider.Primitives.getAll(), + ); const fileName = `built-in-value-types.md`; writeFileSync(join(docsPath, fileName), valueTypeDoc, { diff --git a/apps/docs/generator/src/user-doc-generator.ts b/apps/docs/generator/src/user-doc-generator.ts index 39e2349f..cf458fc6 100644 --- a/apps/docs/generator/src/user-doc-generator.ts +++ b/apps/docs/generator/src/user-doc-generator.ts @@ -26,9 +26,7 @@ export class UserDocGenerator { constructor(private services: JayveeServices) {} - generateValueTypesDoc( - valueTypes: Record, - ): string { + generateValueTypesDoc(valueTypes: PrimitiveValueType[]): string { const builder = new UserDocMarkdownBuilder() .docTitle('Built-in Value Types') .generationComment() @@ -42,16 +40,15 @@ that fullfil [_constraints_](./primitive-value-types#constraints).`.trim(), ) .heading('Available built-in value types', 1); - Object.entries(valueTypes) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .filter(([_, valueType]) => valueType.isReferenceableByUser()) - .forEach(([name, valueType]) => { + valueTypes + .filter((valueType) => valueType.isReferenceableByUser()) + .forEach((valueType) => { assert( valueType.getUserDoc(), `Documentation is missing for user extendable value type: ${valueType.getName()}`, ); builder - .heading(name, 2) + .heading(valueType.getName(), 2) .description(valueType.getUserDoc() ?? '', 3) .examples( [ diff --git a/libs/execution/src/lib/blocks/composite-block-executor.ts b/libs/execution/src/lib/blocks/composite-block-executor.ts index f8470713..92008920 100644 --- a/libs/execution/src/lib/blocks/composite-block-executor.ts +++ b/libs/execution/src/lib/blocks/composite-block-executor.ts @@ -14,7 +14,6 @@ import { type InternalValueRepresentation, type ValueType, type WrapperFactoryProvider, - createValueType, evaluateExpression, evaluatePropertyValue, getIOType, @@ -121,7 +120,9 @@ export function createCompositeBlockExecutor( context: ExecutionContext, ) { properties.forEach((blockTypeProperty) => { - const valueType = createValueType(blockTypeProperty.valueType); + const valueType = context.wrapperFactories.ValueType.wrap( + blockTypeProperty.valueType, + ); assert( valueType, 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 0c472639..9bb4ad88 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 @@ -5,6 +5,7 @@ import { type BlockDefinition, type InternalValueRepresentation, + type JayveeServices, type TypedConstraintDefinition, createJayveeServices, } from '@jvalue/jayvee-language-server'; @@ -32,6 +33,7 @@ describe('Validation of AllowlistConstraintExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -57,13 +59,16 @@ describe('Validation of AllowlistConstraintExecutor', () => { return new AllowlistConstraintExecutor().isValid( value, // Execution context with initial stack containing usage block of constraint and constraint itself - getTestExecutionContext(locator, document, [usageBlock, constraint]), + getTestExecutionContext(locator, document, services, [ + usageBlock, + constraint, + ]), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/execution/src/lib/constraints/executors/allowlist-constraint-executor.ts b/libs/execution/src/lib/constraints/executors/allowlist-constraint-executor.ts index 8b093ab9..5bffbff3 100644 --- a/libs/execution/src/lib/constraints/executors/allowlist-constraint-executor.ts +++ b/libs/execution/src/lib/constraints/executors/allowlist-constraint-executor.ts @@ -2,11 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { - CollectionValuetype, - type InternalValueRepresentation, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; +import { type InternalValueRepresentation } from '@jvalue/jayvee-language-server'; import { type ExecutionContext } from '../../execution-context'; import { implementsStatic } from '../../util/implements-static-decorator'; @@ -27,7 +23,9 @@ export class AllowlistConstraintExecutor implements ConstraintExecutor { const allowlist = context.getPropertyValue( 'allowlist', - new CollectionValuetype(PrimitiveValuetypes.Text), + context.valueTypeProvider.createCollectionValueTypeOf( + context.valueTypeProvider.Primitives.Text, + ), ); return allowlist.includes(value); } 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 52033b16..86e08e0f 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 @@ -5,6 +5,7 @@ import { type BlockDefinition, type InternalValueRepresentation, + type JayveeServices, type TypedConstraintDefinition, createJayveeServices, } from '@jvalue/jayvee-language-server'; @@ -32,6 +33,7 @@ describe('Validation of DenylistConstraintExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -57,13 +59,16 @@ describe('Validation of DenylistConstraintExecutor', () => { return new DenylistConstraintExecutor().isValid( value, // Execution context with initial stack containing usage block of constraint and constraint itself - getTestExecutionContext(locator, document, [usageBlock, constraint]), + getTestExecutionContext(locator, document, services, [ + usageBlock, + constraint, + ]), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/execution/src/lib/constraints/executors/denylist-constraint-executor.ts b/libs/execution/src/lib/constraints/executors/denylist-constraint-executor.ts index 465fcb47..e5494421 100644 --- a/libs/execution/src/lib/constraints/executors/denylist-constraint-executor.ts +++ b/libs/execution/src/lib/constraints/executors/denylist-constraint-executor.ts @@ -2,11 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { - CollectionValuetype, - type InternalValueRepresentation, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; +import { type InternalValueRepresentation } from '@jvalue/jayvee-language-server'; import { type ExecutionContext } from '../../execution-context'; import { implementsStatic } from '../../util/implements-static-decorator'; @@ -27,7 +23,9 @@ export class DenylistConstraintExecutor implements ConstraintExecutor { const denylist = context.getPropertyValue( 'denylist', - new CollectionValuetype(PrimitiveValuetypes.Text), + context.valueTypeProvider.createCollectionValueTypeOf( + context.valueTypeProvider.Primitives.Text, + ), ); return !denylist.includes(value); } 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 83015661..eb64d079 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 @@ -6,6 +6,7 @@ import { type BlockDefinition, type ExpressionConstraintDefinition, type InternalValueRepresentation, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -32,6 +33,7 @@ describe('Validation of AllowlistConstraintExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -57,13 +59,16 @@ describe('Validation of AllowlistConstraintExecutor', () => { return new ExpressionConstraintExecutor(constraint).isValid( value, // Execution context with initial stack containing usage block of constraint and constraint itself - getTestExecutionContext(locator, document, [usageBlock, constraint]), + getTestExecutionContext(locator, document, services, [ + usageBlock, + constraint, + ]), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/execution/src/lib/constraints/executors/expression-constraint-executor.ts b/libs/execution/src/lib/constraints/executors/expression-constraint-executor.ts index 0bbc6a78..a9b69fd9 100644 --- a/libs/execution/src/lib/constraints/executors/expression-constraint-executor.ts +++ b/libs/execution/src/lib/constraints/executors/expression-constraint-executor.ts @@ -8,7 +8,6 @@ import { type AstNodeWrapper, type ExpressionConstraintDefinition, type InternalValueRepresentation, - PrimitiveValuetypes, evaluateExpression, } from '@jvalue/jayvee-language-server'; @@ -33,7 +32,11 @@ export class ExpressionConstraintExecutor context.evaluationContext, context.wrapperFactories, ); - assert(PrimitiveValuetypes.Boolean.isInternalValueRepresentation(result)); + assert( + context.valueTypeProvider.Primitives.Boolean.isInternalValueRepresentation( + result, + ), + ); context.evaluationContext.deleteValueForValueKeyword(); 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 5f6524bc..e8dfec3a 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 @@ -5,6 +5,7 @@ import { type BlockDefinition, type InternalValueRepresentation, + type JayveeServices, type TypedConstraintDefinition, createJayveeServices, } from '@jvalue/jayvee-language-server'; @@ -32,6 +33,7 @@ describe('Validation of LengthConstraintExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -57,13 +59,16 @@ describe('Validation of LengthConstraintExecutor', () => { return new LengthConstraintExecutor().isValid( value, // Execution context with initial stack containing usage block of constraint and constraint itself - getTestExecutionContext(locator, document, [usageBlock, constraint]), + getTestExecutionContext(locator, document, services, [ + usageBlock, + constraint, + ]), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/execution/src/lib/constraints/executors/length-constraint-executor.ts b/libs/execution/src/lib/constraints/executors/length-constraint-executor.ts index 0758ee79..6302c99d 100644 --- a/libs/execution/src/lib/constraints/executors/length-constraint-executor.ts +++ b/libs/execution/src/lib/constraints/executors/length-constraint-executor.ts @@ -2,10 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { - type InternalValueRepresentation, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; +import { type InternalValueRepresentation } from '@jvalue/jayvee-language-server'; import { type ExecutionContext } from '../../execution-context'; import { implementsStatic } from '../../util/implements-static-decorator'; @@ -26,11 +23,11 @@ export class LengthConstraintExecutor implements ConstraintExecutor { const minLength = context.getPropertyValue( 'minLength', - PrimitiveValuetypes.Integer, + context.valueTypeProvider.Primitives.Integer, ); const maxLength = context.getPropertyValue( 'maxLength', - PrimitiveValuetypes.Integer, + context.valueTypeProvider.Primitives.Integer, ); return minLength <= value.length && value.length <= maxLength; 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 14ee14bf..571be846 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 @@ -5,6 +5,7 @@ import { type BlockDefinition, type InternalValueRepresentation, + type JayveeServices, type TypedConstraintDefinition, createJayveeServices, initializeWorkspace, @@ -33,6 +34,7 @@ describe('Validation of RangeConstraintExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -58,13 +60,16 @@ describe('Validation of RangeConstraintExecutor', () => { return new RangeConstraintExecutor().isValid( value, // Execution context with initial stack containing usage block of constraint and constraint itself - getTestExecutionContext(locator, document, [usageBlock, constraint]), + getTestExecutionContext(locator, document, services, [ + usageBlock, + constraint, + ]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await initializeWorkspace(services); locator = services.workspace.AstNodeLocator; diff --git a/libs/execution/src/lib/constraints/executors/range-constraint-executor.ts b/libs/execution/src/lib/constraints/executors/range-constraint-executor.ts index 61c3c422..7b415bd4 100644 --- a/libs/execution/src/lib/constraints/executors/range-constraint-executor.ts +++ b/libs/execution/src/lib/constraints/executors/range-constraint-executor.ts @@ -2,10 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { - type InternalValueRepresentation, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; +import { type InternalValueRepresentation } from '@jvalue/jayvee-language-server'; import { type ExecutionContext } from '../../execution-context'; import { implementsStatic } from '../../util/implements-static-decorator'; @@ -31,19 +28,19 @@ export class RangeConstraintExecutor implements ConstraintExecutor { const lowerBound = context.getPropertyValue( 'lowerBound', - PrimitiveValuetypes.Decimal, + context.valueTypeProvider.Primitives.Decimal, ); const lowerBoundInclusive = context.getPropertyValue( 'lowerBoundInclusive', - PrimitiveValuetypes.Boolean, + context.valueTypeProvider.Primitives.Boolean, ); const upperBound = context.getPropertyValue( 'upperBound', - PrimitiveValuetypes.Decimal, + context.valueTypeProvider.Primitives.Decimal, ); const upperBoundInclusive = context.getPropertyValue( 'upperBoundInclusive', - PrimitiveValuetypes.Boolean, + context.valueTypeProvider.Primitives.Boolean, ); const lowerBoundFulfilled = lowerBoundInclusive 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 8866eeb2..8bbd9ace 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 @@ -5,6 +5,7 @@ import { type BlockDefinition, type InternalValueRepresentation, + type JayveeServices, type TypedConstraintDefinition, createJayveeServices, } from '@jvalue/jayvee-language-server'; @@ -32,6 +33,7 @@ describe('Validation of RegexConstraintExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -57,13 +59,16 @@ describe('Validation of RegexConstraintExecutor', () => { return new RegexConstraintExecutor().isValid( value, // Execution context with initial stack containing usage block of constraint and constraint itself - getTestExecutionContext(locator, document, [usageBlock, constraint]), + getTestExecutionContext(locator, document, services, [ + usageBlock, + constraint, + ]), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/execution/src/lib/constraints/executors/regex-constraint-executor.ts b/libs/execution/src/lib/constraints/executors/regex-constraint-executor.ts index 91bd2628..8548a249 100644 --- a/libs/execution/src/lib/constraints/executors/regex-constraint-executor.ts +++ b/libs/execution/src/lib/constraints/executors/regex-constraint-executor.ts @@ -2,10 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { - type InternalValueRepresentation, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; +import { type InternalValueRepresentation } from '@jvalue/jayvee-language-server'; import { type ExecutionContext } from '../../execution-context'; import { implementsStatic } from '../../util/implements-static-decorator'; @@ -24,7 +21,10 @@ export class RegexConstraintExecutor implements ConstraintExecutor { return false; } - const regex = context.getPropertyValue('regex', PrimitiveValuetypes.Regex); + const regex = context.getPropertyValue( + 'regex', + context.valueTypeProvider.Primitives.Regex, + ); return regex.test(value); } } diff --git a/libs/execution/src/lib/execution-context.ts b/libs/execution/src/lib/execution-context.ts index 159a1978..58bf95bc 100644 --- a/libs/execution/src/lib/execution-context.ts +++ b/libs/execution/src/lib/execution-context.ts @@ -13,6 +13,7 @@ import { type PropertyAssignment, type TransformDefinition, type ValueType, + type ValueTypeProvider, type WrapperFactoryProvider, evaluatePropertyValue, isBlockDefinition, @@ -46,6 +47,7 @@ export class ExecutionContext { public readonly constraintExtension: JayveeConstraintExtension, public readonly logger: Logger, public readonly wrapperFactories: WrapperFactoryProvider, + public readonly valueTypeProvider: ValueTypeProvider, public readonly runOptions: { isDebugMode: boolean; debugGranularity: DebugGranularity; diff --git a/libs/execution/src/lib/transforms/transform-executor.spec.ts b/libs/execution/src/lib/transforms/transform-executor.spec.ts index bc639629..4fa4a857 100644 --- a/libs/execution/src/lib/transforms/transform-executor.spec.ts +++ b/libs/execution/src/lib/transforms/transform-executor.spec.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import { type InternalValueRepresentation, - PrimitiveValuetypes, + type JayveeServices, type TransformDefinition, createJayveeServices, } from '@jvalue/jayvee-language-server'; @@ -37,6 +37,7 @@ describe('Validation of TransformExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -79,18 +80,24 @@ describe('Validation of TransformExecutor', () => { document.parseResult.value, 'transforms@0', ) as TransformDefinition; - const executor = new TransformExecutor(transform); + + const executionContext = getTestExecutionContext( + locator, + document, + services, + ); + const executor = new TransformExecutor(transform, executionContext); return executor.executeTransform( getColumnsMap(columnNames, inputTable, executor.getInputDetails()), inputTable.getNumberOfRows(), - getTestExecutionContext(locator, document), + executionContext, ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve( @@ -115,14 +122,14 @@ describe('Validation of TransformExecutor', () => { columnName: 'Column1', column: { values: ['value 1'], - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, }, { columnName: 'Column2', column: { values: [20.2], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, ], @@ -138,7 +145,7 @@ describe('Validation of TransformExecutor', () => { expect(result.rowsToDelete).toHaveLength(0); expect(result.resultingColumn.valueType).toEqual( - PrimitiveValuetypes.Integer, + services.ValueTypeProvider.Primitives.Integer, ); expect(result.resultingColumn.values).toHaveLength(1); expect(result.resultingColumn.values).toEqual(expect.arrayContaining([21])); @@ -155,14 +162,14 @@ describe('Validation of TransformExecutor', () => { columnName: 'Column1', column: { values: ['value 1'], - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, }, { columnName: 'Column2', column: { values: [20.0], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, ], @@ -178,7 +185,9 @@ describe('Validation of TransformExecutor', () => { expect(result.rowsToDelete).toHaveLength(1); expect(result.rowsToDelete).toEqual(expect.arrayContaining([0])); - expect(result.resultingColumn.valueType).toEqual(PrimitiveValuetypes.Text); + expect(result.resultingColumn.valueType).toEqual( + services.ValueTypeProvider.Primitives.Text, + ); expect(result.resultingColumn.values).toHaveLength(0); }); @@ -193,21 +202,21 @@ describe('Validation of TransformExecutor', () => { columnName: 'Column1', column: { values: ['value 1'], - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, }, { columnName: 'Column2', column: { values: [20.2], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, { columnName: 'Column3', column: { values: [85.978], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, ], @@ -223,7 +232,7 @@ describe('Validation of TransformExecutor', () => { expect(result.rowsToDelete).toHaveLength(0); expect(result.resultingColumn.valueType).toEqual( - PrimitiveValuetypes.Integer, + services.ValueTypeProvider.Primitives.Integer, ); expect(result.resultingColumn.values).toHaveLength(1); expect(result.resultingColumn.values).toEqual( @@ -242,14 +251,14 @@ describe('Validation of TransformExecutor', () => { columnName: 'Column1', column: { values: ['value 1'], - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, }, { columnName: 'Column2', column: { values: [20.2], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, ], @@ -285,14 +294,14 @@ describe('Validation of TransformExecutor', () => { columnName: 'Column1', column: { values: ['value 1'], - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, }, { columnName: 'Column2', column: { values: [20.2], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, ], @@ -308,7 +317,7 @@ describe('Validation of TransformExecutor', () => { expect(result.rowsToDelete).toHaveLength(1); expect(result.resultingColumn.valueType).toEqual( - PrimitiveValuetypes.Integer, + services.ValueTypeProvider.Primitives.Integer, ); expect(result.resultingColumn.values).toHaveLength(0); }); @@ -324,14 +333,14 @@ describe('Validation of TransformExecutor', () => { columnName: 'Column1', column: { values: ['value 1', 'value 2'], - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, }, { columnName: 'Column2', column: { values: ['20.2', 20.1], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, ], @@ -347,7 +356,7 @@ describe('Validation of TransformExecutor', () => { expect(result.rowsToDelete).toHaveLength(1); expect(result.resultingColumn.valueType).toEqual( - PrimitiveValuetypes.Integer, + services.ValueTypeProvider.Primitives.Integer, ); expect(result.resultingColumn.values).toHaveLength(1); expect(result.resultingColumn.values).toEqual(expect.arrayContaining([21])); @@ -364,21 +373,21 @@ describe('Validation of TransformExecutor', () => { columnName: 'Column1', column: { values: ['value 1'], - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, }, { columnName: 'Column2', column: { values: [20.2], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, { columnName: 'Column3', column: { values: [85.978], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, ], @@ -394,7 +403,7 @@ describe('Validation of TransformExecutor', () => { expect(result.rowsToDelete).toHaveLength(1); expect(result.resultingColumn.valueType).toEqual( - PrimitiveValuetypes.Decimal, + services.ValueTypeProvider.Primitives.Decimal, ); expect(result.resultingColumn.values).toHaveLength(0); }); diff --git a/libs/execution/src/lib/transforms/transform-executor.ts b/libs/execution/src/lib/transforms/transform-executor.ts index 444636b8..4647b19a 100644 --- a/libs/execution/src/lib/transforms/transform-executor.ts +++ b/libs/execution/src/lib/transforms/transform-executor.ts @@ -10,7 +10,6 @@ import { type TransformOutputAssignment, type TransformPortDefinition, type ValueType, - createValueType, evaluateExpression, } from '@jvalue/jayvee-language-server'; @@ -24,7 +23,10 @@ export interface PortDetails { } export class TransformExecutor { - constructor(private readonly transform: TransformDefinition) {} + constructor( + private readonly transform: TransformDefinition, + private readonly context: ExecutionContext, + ) {} getInputDetails(): PortDetails[] { return this.getPortDetails('from'); @@ -44,7 +46,8 @@ export class TransformExecutor { const ports = this.transform.body.ports.filter((x) => x.kind === kind); const portDetails = ports.map((port) => { const valueTypeNode = port.valueType; - const valueType = createValueType(valueTypeNode); + const valueType = + this.context.wrapperFactories.ValueType.wrap(valueTypeNode); assert(valueType !== undefined); return { port: port, diff --git a/libs/execution/src/lib/types/io-types/table.spec.ts b/libs/execution/src/lib/types/io-types/table.spec.ts index 3603890b..0575e26c 100644 --- a/libs/execution/src/lib/types/io-types/table.spec.ts +++ b/libs/execution/src/lib/types/io-types/table.spec.ts @@ -2,21 +2,29 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { ValueTypeProvider } from '@jvalue/jayvee-language-server'; import { Table } from './table'; describe('Table', () => { let table: Table; + let valueTypeProvider: ValueTypeProvider; beforeEach(() => { table = new Table(); + valueTypeProvider = new ValueTypeProvider(); }); describe('addColumn', () => { it('should increase the number of columns correctly on adding columns', () => { - table.addColumn('a', { valueType: PrimitiveValuetypes.Text, values: [] }); - table.addColumn('b', { valueType: PrimitiveValuetypes.Text, values: [] }); + table.addColumn('a', { + valueType: valueTypeProvider.Primitives.Text, + values: [], + }); + table.addColumn('b', { + valueType: valueTypeProvider.Primitives.Text, + values: [], + }); expect(table.getNumberOfColumns()).toBe(2); }); @@ -25,14 +33,14 @@ describe('Table', () => { describe('addRow', () => { it('should increase the number of rows correctly and allow adding columns afterwards', () => { table.addColumn('a', { - valueType: PrimitiveValuetypes.Text, + valueType: valueTypeProvider.Primitives.Text, values: [], }); table.addRow({ a: 'a1' }); table.addRow({ a: 'a2' }); table.addRow({ a: 'a3' }); table.addColumn('b', { - valueType: PrimitiveValuetypes.Text, + valueType: valueTypeProvider.Primitives.Text, values: ['b1', 'b2', 'b3'], }); @@ -41,7 +49,7 @@ describe('Table', () => { it('should increase the number of rows correctly on adding a row and a given column structure', () => { table.addColumn('a', { - valueType: PrimitiveValuetypes.Text, + valueType: valueTypeProvider.Primitives.Text, values: [], }); table.addRow({ a: 'a1' }); diff --git a/libs/execution/src/lib/types/value-types/internal-representation-parsing.ts b/libs/execution/src/lib/types/value-types/internal-representation-parsing.ts index af599f91..bc4ce7ef 100644 --- a/libs/execution/src/lib/types/value-types/internal-representation-parsing.ts +++ b/libs/execution/src/lib/types/value-types/internal-representation-parsing.ts @@ -5,7 +5,7 @@ import { strict as assert } from 'assert'; import { - type AtomicValuetype, + type AtomicValueType, type InternalValueRepresentation, type ValueType, ValueTypeVisitor, @@ -76,8 +76,8 @@ class InternalRepresentationParserVisitor extends ValueTypeVisitor< return this.value; } - visitAtomicValuetype( - valueType: AtomicValuetype, + visitAtomicValueType( + valueType: AtomicValueType, ): InternalValueRepresentation | undefined { const supertype = valueType.getSupertype(); assert(supertype !== undefined); diff --git a/libs/execution/src/lib/types/value-types/value-representation-validity.ts b/libs/execution/src/lib/types/value-types/value-representation-validity.ts index a3e33770..97211471 100644 --- a/libs/execution/src/lib/types/value-types/value-representation-validity.ts +++ b/libs/execution/src/lib/types/value-types/value-representation-validity.ts @@ -5,10 +5,10 @@ import { strict as assert } from 'assert'; import { - type AtomicValuetype, + type AtomicValueType, type BooleanValuetype, type CellRangeValuetype, - type CollectionValuetype, + type CollectionValueType, type ConstraintValuetype, type DecimalValuetype, type IntegerValuetype, @@ -41,7 +41,7 @@ class ValueRepresentationValidityVisitor extends ValueTypeVisitor { super(); } - override visitAtomicValuetype(valueType: AtomicValuetype): boolean { + override visitAtomicValueType(valueType: AtomicValueType): boolean { const supertype = valueType.getSupertype(); assert(supertype !== undefined); if (!supertype.acceptVisitor(this)) { @@ -50,7 +50,6 @@ class ValueRepresentationValidityVisitor extends ValueTypeVisitor { const constraints = valueType.getConstraints( this.context.evaluationContext, - this.context.wrapperFactories, ); for (const constraint of constraints) { const constraintExecutor = @@ -105,7 +104,7 @@ class ValueRepresentationValidityVisitor extends ValueTypeVisitor { return this.isValidForPrimitiveValuetype(valueType); } - override visitCollection(valueType: CollectionValuetype): boolean { + override visitCollection(valueType: CollectionValueType): boolean { return this.isValidForPrimitiveValuetype(valueType); } diff --git a/libs/execution/src/lib/types/value-types/visitors/sql-column-type-visitor.ts b/libs/execution/src/lib/types/value-types/visitors/sql-column-type-visitor.ts index 2f3e2dc3..de86854c 100644 --- a/libs/execution/src/lib/types/value-types/visitors/sql-column-type-visitor.ts +++ b/libs/execution/src/lib/types/value-types/visitors/sql-column-type-visitor.ts @@ -5,7 +5,7 @@ import { strict as assert } from 'assert'; import { - type AtomicValuetype, + type AtomicValueType, ValueTypeVisitor, } from '@jvalue/jayvee-language-server'; @@ -26,7 +26,7 @@ export class SQLColumnTypeVisitor extends ValueTypeVisitor { return 'text'; } - override visitAtomicValuetype(valueType: AtomicValuetype): string { + override visitAtomicValueType(valueType: AtomicValueType): string { const supertype = valueType.getSupertype(); assert(supertype !== undefined); return supertype.acceptVisitor(this); diff --git a/libs/execution/src/lib/types/value-types/visitors/sql-value-representation-visitor.ts b/libs/execution/src/lib/types/value-types/visitors/sql-value-representation-visitor.ts index d251b177..a44f3835 100644 --- a/libs/execution/src/lib/types/value-types/visitors/sql-value-representation-visitor.ts +++ b/libs/execution/src/lib/types/value-types/visitors/sql-value-representation-visitor.ts @@ -5,7 +5,7 @@ import { strict as assert } from 'assert'; import { - type AtomicValuetype, + type AtomicValueType, type BooleanValuetype, type DecimalValuetype, type IntegerValuetype, @@ -54,8 +54,8 @@ export class SQLValueRepresentationVisitor extends ValueTypeVisitor< }; } - override visitAtomicValuetype( - valueType: AtomicValuetype, + override visitAtomicValueType( + valueType: AtomicValueType, ): (value: InternalValueRepresentation) => string { const supertype = valueType.getSupertype(); assert(supertype !== undefined); diff --git a/libs/execution/test/utils/test-infrastructure-util.ts b/libs/execution/test/utils/test-infrastructure-util.ts index 10772169..572d1458 100644 --- a/libs/execution/test/utils/test-infrastructure-util.ts +++ b/libs/execution/test/utils/test-infrastructure-util.ts @@ -3,11 +3,9 @@ // SPDX-License-Identifier: AGPL-3.0-only import { - DefaultOperatorEvaluatorRegistry, EvaluationContext, + type JayveeServices, type PipelineDefinition, - RuntimeParameterProvider, - WrapperFactoryProvider, } from '@jvalue/jayvee-language-server'; import { type AstNode, @@ -44,6 +42,7 @@ export function processExitMockImplementation(code?: number) { export function getTestExecutionContext( locator: AstNodeLocator, document: LangiumDocument, + services: JayveeServices, initialStack: StackNode[] = [], runOptions: { isDebugMode: boolean; @@ -61,18 +60,18 @@ export function getTestExecutionContext( 'pipelines@0', ) as PipelineDefinition; - const operatorEvaluatorRegistry = new DefaultOperatorEvaluatorRegistry(); - const executionContext = new ExecutionContext( pipeline, new TestExecExtension(), new DefaultConstraintExtension(), new CachedLogger(runOptions.isDebugMode, undefined, loggerPrintLogs), - new WrapperFactoryProvider(operatorEvaluatorRegistry), + services.WrapperFactories, + services.ValueTypeProvider, runOptions, new EvaluationContext( - new RuntimeParameterProvider(), - operatorEvaluatorRegistry, + services.RuntimeParameterProvider, + services.operators.EvaluatorRegistry, + services.ValueTypeProvider, ), ); diff --git a/libs/extensions/rdbms/exec/src/lib/postgres-loader-executor.spec.ts b/libs/extensions/rdbms/exec/src/lib/postgres-loader-executor.spec.ts index 0672cb78..28f6d568 100644 --- a/libs/extensions/rdbms/exec/src/lib/postgres-loader-executor.spec.ts +++ b/libs/extensions/rdbms/exec/src/lib/postgres-loader-executor.spec.ts @@ -12,7 +12,7 @@ import { import { type BlockDefinition, IOType, - PrimitiveValuetypes, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -56,6 +56,7 @@ describe('Validation of PostgresLoaderExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -76,13 +77,13 @@ describe('Validation of PostgresLoaderExecutor', () => { return new PostgresLoaderExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../../test/test-extension/TestBlockTypes.jv'), ]); @@ -103,14 +104,14 @@ describe('Validation of PostgresLoaderExecutor', () => { columnName: 'Column1', column: { values: ['value 1'], - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, }, { columnName: 'Column2', column: { values: [20.2], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, ], @@ -147,14 +148,14 @@ describe('Validation of PostgresLoaderExecutor', () => { columnName: 'Column1', column: { values: ['value 1'], - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, }, { columnName: 'Column2', column: { values: [20.2], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, ], diff --git a/libs/extensions/rdbms/exec/src/lib/postgres-loader-executor.ts b/libs/extensions/rdbms/exec/src/lib/postgres-loader-executor.ts index 7e3cf5bc..b4afec13 100644 --- a/libs/extensions/rdbms/exec/src/lib/postgres-loader-executor.ts +++ b/libs/extensions/rdbms/exec/src/lib/postgres-loader-executor.ts @@ -12,7 +12,7 @@ import { Table, implementsStatic, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; import { Client } from 'pg'; @implementsStatic() @@ -30,18 +30,30 @@ export class PostgresLoaderExecutor extends AbstractBlockExecutor< input: Table, context: ExecutionContext, ): Promise> { - const host = context.getPropertyValue('host', PrimitiveValuetypes.Text); - const port = context.getPropertyValue('port', PrimitiveValuetypes.Integer); - const user = context.getPropertyValue('username', PrimitiveValuetypes.Text); + const host = context.getPropertyValue( + 'host', + context.valueTypeProvider.Primitives.Text, + ); + const port = context.getPropertyValue( + 'port', + context.valueTypeProvider.Primitives.Integer, + ); + const user = context.getPropertyValue( + 'username', + context.valueTypeProvider.Primitives.Text, + ); const password = context.getPropertyValue( 'password', - PrimitiveValuetypes.Text, + context.valueTypeProvider.Primitives.Text, ); const database = context.getPropertyValue( 'database', - PrimitiveValuetypes.Text, + context.valueTypeProvider.Primitives.Text, + ); + const table = context.getPropertyValue( + 'table', + context.valueTypeProvider.Primitives.Text, ); - const table = context.getPropertyValue('table', PrimitiveValuetypes.Text); const client = new Client({ host, diff --git a/libs/extensions/rdbms/exec/src/lib/sqlite-loader-executor.spec.ts b/libs/extensions/rdbms/exec/src/lib/sqlite-loader-executor.spec.ts index fa1f9337..25852951 100644 --- a/libs/extensions/rdbms/exec/src/lib/sqlite-loader-executor.spec.ts +++ b/libs/extensions/rdbms/exec/src/lib/sqlite-loader-executor.spec.ts @@ -12,7 +12,7 @@ import { import { type BlockDefinition, IOType, - PrimitiveValuetypes, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -67,6 +67,7 @@ describe('Validation of SQLiteLoaderExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -87,13 +88,13 @@ describe('Validation of SQLiteLoaderExecutor', () => { return new SQLiteLoaderExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../../test/test-extension/TestBlockTypes.jv'), ]); @@ -127,14 +128,14 @@ describe('Validation of SQLiteLoaderExecutor', () => { columnName: 'Column1', column: { values: ['value 1'], - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, }, { columnName: 'Column2', column: { values: [20.2], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, ], @@ -177,14 +178,14 @@ describe('Validation of SQLiteLoaderExecutor', () => { columnName: 'Column1', column: { values: ['value 1'], - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, }, { columnName: 'Column2', column: { values: [20.2], - valueType: PrimitiveValuetypes.Decimal, + valueType: services.ValueTypeProvider.Primitives.Decimal, }, }, ], diff --git a/libs/extensions/rdbms/exec/src/lib/sqlite-loader-executor.ts b/libs/extensions/rdbms/exec/src/lib/sqlite-loader-executor.ts index 38d2ed46..66aa6195 100644 --- a/libs/extensions/rdbms/exec/src/lib/sqlite-loader-executor.ts +++ b/libs/extensions/rdbms/exec/src/lib/sqlite-loader-executor.ts @@ -12,7 +12,7 @@ import { Table, implementsStatic, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; import * as sqlite3 from 'sqlite3'; @implementsStatic() @@ -30,11 +30,17 @@ export class SQLiteLoaderExecutor extends AbstractBlockExecutor< input: Table, context: ExecutionContext, ): Promise> { - const file = context.getPropertyValue('file', PrimitiveValuetypes.Text); - const table = context.getPropertyValue('table', PrimitiveValuetypes.Text); + const file = context.getPropertyValue( + 'file', + context.valueTypeProvider.Primitives.Text, + ); + const table = context.getPropertyValue( + 'table', + context.valueTypeProvider.Primitives.Text, + ); const dropTable = context.getPropertyValue( 'dropTable', - PrimitiveValuetypes.Boolean, + context.valueTypeProvider.Primitives.Boolean, ); let db: sqlite3.Database | undefined; diff --git a/libs/extensions/std/exec/src/archive-interpreter-executor.spec.ts b/libs/extensions/std/exec/src/archive-interpreter-executor.spec.ts index 65b5a85d..0340c443 100644 --- a/libs/extensions/std/exec/src/archive-interpreter-executor.spec.ts +++ b/libs/extensions/std/exec/src/archive-interpreter-executor.spec.ts @@ -12,6 +12,7 @@ import { import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -37,7 +38,7 @@ describe('Validation of ArchiveInterpreterExecutor', () => { ) => Promise>; let locator: AstNodeLocator; - + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, '../test/assets/archive-interpreter-executor/', @@ -66,13 +67,13 @@ describe('Validation of ArchiveInterpreterExecutor', () => { return new ArchiveInterpreterExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/std/exec/src/archive-interpreter-executor.ts b/libs/extensions/std/exec/src/archive-interpreter-executor.ts index 3dc92ee4..d0491fdc 100644 --- a/libs/extensions/std/exec/src/archive-interpreter-executor.ts +++ b/libs/extensions/std/exec/src/archive-interpreter-executor.ts @@ -21,7 +21,7 @@ import { inferFileExtensionFromFileExtensionString, inferMimeTypeFromFileExtensionString, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; import * as JSZip from 'jszip'; @implementsStatic() @@ -41,7 +41,7 @@ export class ArchiveInterpreterExecutor extends AbstractBlockExecutor< ): Promise> { const archiveType = context.getPropertyValue( 'archiveType', - PrimitiveValuetypes.Text, + context.valueTypeProvider.Primitives.Text, ); let fs: R.Result; diff --git a/libs/extensions/std/exec/src/file-picker-executor.spec.ts b/libs/extensions/std/exec/src/file-picker-executor.spec.ts index d7812d6b..917888e5 100644 --- a/libs/extensions/std/exec/src/file-picker-executor.spec.ts +++ b/libs/extensions/std/exec/src/file-picker-executor.spec.ts @@ -12,6 +12,7 @@ import { import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -38,6 +39,7 @@ describe('Validation of FilePickerExecutor', () => { let fileSystem: R.FileSystem; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -70,13 +72,13 @@ describe('Validation of FilePickerExecutor', () => { return new FilePickerExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/std/exec/src/file-picker-executor.ts b/libs/extensions/std/exec/src/file-picker-executor.ts index a1916037..b57b50fc 100644 --- a/libs/extensions/std/exec/src/file-picker-executor.ts +++ b/libs/extensions/std/exec/src/file-picker-executor.ts @@ -13,7 +13,7 @@ import { type FileSystem, implementsStatic, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; @implementsStatic() export class FilePickerExecutor extends AbstractBlockExecutor< @@ -31,7 +31,10 @@ export class FilePickerExecutor extends AbstractBlockExecutor< fileSystem: FileSystem, context: ExecutionContext, ): Promise> { - const path = context.getPropertyValue('path', PrimitiveValuetypes.Text); + const path = context.getPropertyValue( + 'path', + context.valueTypeProvider.Primitives.Text, + ); const file = fileSystem.getFile(path); if (file == null) { return R.err({ diff --git a/libs/extensions/std/exec/src/gtfs-rt-interpreter-executor.spec.ts b/libs/extensions/std/exec/src/gtfs-rt-interpreter-executor.spec.ts index a05f3cd6..bea4fb49 100644 --- a/libs/extensions/std/exec/src/gtfs-rt-interpreter-executor.spec.ts +++ b/libs/extensions/std/exec/src/gtfs-rt-interpreter-executor.spec.ts @@ -12,6 +12,7 @@ import { import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -37,6 +38,7 @@ describe('Validation of GtfsRTInterpreterExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -66,13 +68,13 @@ describe('Validation of GtfsRTInterpreterExecutor', () => { return new GtfsRTInterpreterExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/std/exec/src/gtfs-rt-interpreter-executor.ts b/libs/extensions/std/exec/src/gtfs-rt-interpreter-executor.ts index f370af29..c3f1f4cf 100644 --- a/libs/extensions/std/exec/src/gtfs-rt-interpreter-executor.ts +++ b/libs/extensions/std/exec/src/gtfs-rt-interpreter-executor.ts @@ -11,7 +11,7 @@ import { Sheet, implementsStatic, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; import * as E from 'fp-ts/lib/Either'; import { type Either } from 'fp-ts/lib/Either'; import * as GtfsRealtimeBindings from 'gtfs-realtime-bindings'; @@ -32,7 +32,10 @@ export class GtfsRTInterpreterExecutor extends AbstractBlockExecutor< context: ExecutionContext, ): Promise> { // Accessing attribute values by their name: - const entity = context.getPropertyValue('entity', PrimitiveValuetypes.Text); + const entity = context.getPropertyValue( + 'entity', + context.valueTypeProvider.Primitives.Text, + ); // https://github.com/MobilityData/gtfs-realtime-bindings/tree/master/nodejs let feedMessage; diff --git a/libs/extensions/std/exec/src/http-extractor-executor.spec.ts b/libs/extensions/std/exec/src/http-extractor-executor.spec.ts index d91a9122..a28de076 100644 --- a/libs/extensions/std/exec/src/http-extractor-executor.spec.ts +++ b/libs/extensions/std/exec/src/http-extractor-executor.spec.ts @@ -9,6 +9,7 @@ import { getTestExecutionContext } from '@jvalue/jayvee-execution/test'; import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -35,6 +36,7 @@ describe('Validation of HttpExtractorExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -54,13 +56,13 @@ describe('Validation of HttpExtractorExecutor', () => { return new HttpExtractorExecutor().doExecute( R.NONE, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/std/exec/src/http-extractor-executor.ts b/libs/extensions/std/exec/src/http-extractor-executor.ts index b898ce23..8e565c63 100644 --- a/libs/extensions/std/exec/src/http-extractor-executor.ts +++ b/libs/extensions/std/exec/src/http-extractor-executor.ts @@ -20,7 +20,7 @@ import { inferFileExtensionFromFileExtensionString, inferMimeTypeFromFileExtensionString, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; import { http, https } from 'follow-redirects'; import { type AstNode } from 'langium'; @@ -46,19 +46,22 @@ export class HttpExtractorExecutor extends AbstractBlockExecutor< input: None, context: ExecutionContext, ): Promise> { - const url = context.getPropertyValue('url', PrimitiveValuetypes.Text); + const url = context.getPropertyValue( + 'url', + context.valueTypeProvider.Primitives.Text, + ); const retries = context.getPropertyValue( 'retries', - PrimitiveValuetypes.Integer, + context.valueTypeProvider.Primitives.Integer, ); assert(retries >= 0); // loop executes at least once const retryBackoffMilliseconds = context.getPropertyValue( 'retryBackoffMilliseconds', - PrimitiveValuetypes.Integer, + context.valueTypeProvider.Primitives.Integer, ); const retryBackoffStrategy = context.getPropertyValue( 'retryBackoffStrategy', - PrimitiveValuetypes.Text, + context.valueTypeProvider.Primitives.Text, ); assert(isBackoffStrategyHandle(retryBackoffStrategy)); const backoffStrategy = createBackoffStrategy( @@ -109,7 +112,7 @@ export class HttpExtractorExecutor extends AbstractBlockExecutor< } const followRedirects = context.getPropertyValue( 'followRedirects', - PrimitiveValuetypes.Boolean, + context.valueTypeProvider.Primitives.Boolean, ); return new Promise((resolve) => { httpGetFunction(url, { followRedirects: followRedirects }, (response) => { diff --git a/libs/extensions/std/exec/src/local-file-extractor-executor.spec.ts b/libs/extensions/std/exec/src/local-file-extractor-executor.spec.ts index a73fbfb7..df1fa20f 100644 --- a/libs/extensions/std/exec/src/local-file-extractor-executor.spec.ts +++ b/libs/extensions/std/exec/src/local-file-extractor-executor.spec.ts @@ -9,6 +9,7 @@ import { getTestExecutionContext } from '@jvalue/jayvee-execution/test'; import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -31,6 +32,7 @@ describe('Validation of LocalFileExtractorExecutor', () => { let parse: (input: string) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -50,13 +52,13 @@ describe('Validation of LocalFileExtractorExecutor', () => { return new LocalFileExtractorExecutor().doExecute( R.NONE, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/std/exec/src/local-file-extractor-executor.ts b/libs/extensions/std/exec/src/local-file-extractor-executor.ts index 070c8faa..921a357b 100644 --- a/libs/extensions/std/exec/src/local-file-extractor-executor.ts +++ b/libs/extensions/std/exec/src/local-file-extractor-executor.ts @@ -18,7 +18,7 @@ import { inferFileExtensionFromFileExtensionString, inferMimeTypeFromFileExtensionString, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; @implementsStatic() export class LocalFileExtractorExecutor extends AbstractBlockExecutor< @@ -37,7 +37,7 @@ export class LocalFileExtractorExecutor extends AbstractBlockExecutor< ): Promise> { const filePath = context.getPropertyValue( 'filePath', - PrimitiveValuetypes.Text, + context.valueTypeProvider.Primitives.Text, ); if (filePath.includes('..')) { diff --git a/libs/extensions/std/exec/src/text-file-interpreter-executor.spec.ts b/libs/extensions/std/exec/src/text-file-interpreter-executor.spec.ts index ab963ec6..aded5b58 100644 --- a/libs/extensions/std/exec/src/text-file-interpreter-executor.spec.ts +++ b/libs/extensions/std/exec/src/text-file-interpreter-executor.spec.ts @@ -12,6 +12,7 @@ import { import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -37,6 +38,7 @@ describe('Validation of TextFileInterpreterExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -66,13 +68,13 @@ describe('Validation of TextFileInterpreterExecutor', () => { return new TextFileInterpreterExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/std/exec/src/text-file-interpreter-executor.ts b/libs/extensions/std/exec/src/text-file-interpreter-executor.ts index b3ebedf5..1edafdad 100644 --- a/libs/extensions/std/exec/src/text-file-interpreter-executor.ts +++ b/libs/extensions/std/exec/src/text-file-interpreter-executor.ts @@ -14,7 +14,7 @@ import { implementsStatic, splitLines, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; @implementsStatic() export class TextFileInterpreterExecutor extends AbstractBlockExecutor< @@ -34,11 +34,11 @@ export class TextFileInterpreterExecutor extends AbstractBlockExecutor< ): Promise> { const encoding = context.getPropertyValue( 'encoding', - PrimitiveValuetypes.Text, + context.valueTypeProvider.Primitives.Text, ); const lineBreak = context.getPropertyValue( 'lineBreak', - PrimitiveValuetypes.Regex, + context.valueTypeProvider.Primitives.Regex, ); const decoder = new TextDecoder(encoding); diff --git a/libs/extensions/std/exec/src/text-line-deleter-executor.spec.ts b/libs/extensions/std/exec/src/text-line-deleter-executor.spec.ts index 55751ea7..313b78bf 100644 --- a/libs/extensions/std/exec/src/text-line-deleter-executor.spec.ts +++ b/libs/extensions/std/exec/src/text-line-deleter-executor.spec.ts @@ -12,6 +12,7 @@ import { import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -37,6 +38,7 @@ describe('Validation of TextLineDeleterExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -66,13 +68,13 @@ describe('Validation of TextLineDeleterExecutor', () => { return new TextLineDeleterExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/std/exec/src/text-line-deleter-executor.ts b/libs/extensions/std/exec/src/text-line-deleter-executor.ts index b75c92cc..c1fa2179 100644 --- a/libs/extensions/std/exec/src/text-line-deleter-executor.ts +++ b/libs/extensions/std/exec/src/text-line-deleter-executor.ts @@ -10,11 +10,7 @@ import { TextFile, implementsStatic, } from '@jvalue/jayvee-execution'; -import { - CollectionValuetype, - IOType, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; @implementsStatic() export class TextLineDeleterExecutor extends AbstractBlockExecutor< @@ -34,7 +30,9 @@ export class TextLineDeleterExecutor extends AbstractBlockExecutor< ): Promise> { const lines = context.getPropertyValue( 'lines', - new CollectionValuetype(PrimitiveValuetypes.Integer), + context.valueTypeProvider.createCollectionValueTypeOf( + context.valueTypeProvider.Primitives.Integer, + ), ); const numberOfLines = file.content.length; diff --git a/libs/extensions/std/exec/src/text-range-selector-executor.spec.ts b/libs/extensions/std/exec/src/text-range-selector-executor.spec.ts index 7da55604..b5c19d66 100644 --- a/libs/extensions/std/exec/src/text-range-selector-executor.spec.ts +++ b/libs/extensions/std/exec/src/text-range-selector-executor.spec.ts @@ -12,6 +12,7 @@ import { import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -37,6 +38,7 @@ describe('Validation of TextRangeSelectorExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -66,13 +68,13 @@ describe('Validation of TextRangeSelectorExecutor', () => { return new TextRangeSelectorExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/std/exec/src/text-range-selector-executor.ts b/libs/extensions/std/exec/src/text-range-selector-executor.ts index 97b666ef..da71adaa 100644 --- a/libs/extensions/std/exec/src/text-range-selector-executor.ts +++ b/libs/extensions/std/exec/src/text-range-selector-executor.ts @@ -10,7 +10,7 @@ import { TextFile, implementsStatic, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; @implementsStatic() export class TextRangeSelectorExecutor extends AbstractBlockExecutor< @@ -30,11 +30,11 @@ export class TextRangeSelectorExecutor extends AbstractBlockExecutor< ): Promise> { const lineFrom = context.getPropertyValue( 'lineFrom', - PrimitiveValuetypes.Integer, + context.valueTypeProvider.Primitives.Integer, ); const lineTo = context.getPropertyValue( 'lineTo', - PrimitiveValuetypes.Integer, + context.valueTypeProvider.Primitives.Integer, ); const numberOfLines = file.content.length; diff --git a/libs/extensions/tabular/exec/src/lib/cell-range-selector-executor.spec.ts b/libs/extensions/tabular/exec/src/lib/cell-range-selector-executor.spec.ts index 22e2bce0..f12654b6 100644 --- a/libs/extensions/tabular/exec/src/lib/cell-range-selector-executor.spec.ts +++ b/libs/extensions/tabular/exec/src/lib/cell-range-selector-executor.spec.ts @@ -9,6 +9,7 @@ import { getTestExecutionContext } from '@jvalue/jayvee-execution/test'; import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -36,6 +37,7 @@ describe('Validation of CellRangeSelectorExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -65,13 +67,13 @@ describe('Validation of CellRangeSelectorExecutor', () => { return new CellRangeSelectorExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/tabular/exec/src/lib/cell-range-selector-executor.ts b/libs/extensions/tabular/exec/src/lib/cell-range-selector-executor.ts index ed22d619..d0d075fa 100644 --- a/libs/extensions/tabular/exec/src/lib/cell-range-selector-executor.ts +++ b/libs/extensions/tabular/exec/src/lib/cell-range-selector-executor.ts @@ -10,7 +10,7 @@ import { type Sheet, implementsStatic, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; @implementsStatic() export class CellRangeSelectorExecutor extends AbstractBlockExecutor< @@ -30,7 +30,7 @@ export class CellRangeSelectorExecutor extends AbstractBlockExecutor< ): Promise> { const relativeRange = context.getPropertyValue( 'select', - PrimitiveValuetypes.CellRange, + context.valueTypeProvider.Primitives.CellRange, ); const relativeRangeWrapper = context.wrapperFactories.CellRange.wrap(relativeRange); diff --git a/libs/extensions/tabular/exec/src/lib/cell-writer-executor.spec.ts b/libs/extensions/tabular/exec/src/lib/cell-writer-executor.spec.ts index 1f194cf5..e7bce014 100644 --- a/libs/extensions/tabular/exec/src/lib/cell-writer-executor.spec.ts +++ b/libs/extensions/tabular/exec/src/lib/cell-writer-executor.spec.ts @@ -9,6 +9,7 @@ import { getTestExecutionContext } from '@jvalue/jayvee-execution/test'; import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -36,6 +37,7 @@ describe('Validation of CellWriterExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -65,13 +67,13 @@ describe('Validation of CellWriterExecutor', () => { return new CellWriterExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/tabular/exec/src/lib/cell-writer-executor.ts b/libs/extensions/tabular/exec/src/lib/cell-writer-executor.ts index 9d611569..2483a468 100644 --- a/libs/extensions/tabular/exec/src/lib/cell-writer-executor.ts +++ b/libs/extensions/tabular/exec/src/lib/cell-writer-executor.ts @@ -12,11 +12,7 @@ import { type Sheet, implementsStatic, } from '@jvalue/jayvee-execution'; -import { - CollectionValuetype, - IOType, - PrimitiveValuetypes, -} from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; @implementsStatic() export class CellWriterExecutor extends AbstractBlockExecutor< @@ -36,11 +32,13 @@ export class CellWriterExecutor extends AbstractBlockExecutor< ): Promise> { const relativeCellRange = context.getPropertyValue( 'at', - PrimitiveValuetypes.CellRange, + context.valueTypeProvider.Primitives.CellRange, ); const writeValues = context.getPropertyValue( 'write', - new CollectionValuetype(PrimitiveValuetypes.Text), + context.valueTypeProvider.createCollectionValueTypeOf( + context.valueTypeProvider.Primitives.Text, + ), ); const relativeCellRangeWrapper = diff --git a/libs/extensions/tabular/exec/src/lib/column-deleter-executor.spec.ts b/libs/extensions/tabular/exec/src/lib/column-deleter-executor.spec.ts index 00054e53..2b202ce9 100644 --- a/libs/extensions/tabular/exec/src/lib/column-deleter-executor.spec.ts +++ b/libs/extensions/tabular/exec/src/lib/column-deleter-executor.spec.ts @@ -9,6 +9,7 @@ import { getTestExecutionContext } from '@jvalue/jayvee-execution/test'; import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -36,6 +37,7 @@ describe('Validation of ColumnDeleterExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -65,13 +67,13 @@ describe('Validation of ColumnDeleterExecutor', () => { return new ColumnDeleterExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/tabular/exec/src/lib/column-deleter-executor.ts b/libs/extensions/tabular/exec/src/lib/column-deleter-executor.ts index d2129dd9..36906479 100644 --- a/libs/extensions/tabular/exec/src/lib/column-deleter-executor.ts +++ b/libs/extensions/tabular/exec/src/lib/column-deleter-executor.ts @@ -13,10 +13,8 @@ import { implementsStatic, } from '@jvalue/jayvee-execution'; import { - CollectionValuetype, type ColumnWrapper, IOType, - PrimitiveValuetypes, columnIndexToString, getColumnIndex, isColumnWrapper, @@ -41,7 +39,9 @@ export class ColumnDeleterExecutor extends AbstractBlockExecutor< const relativeColumns = context .getPropertyValue( 'delete', - new CollectionValuetype(PrimitiveValuetypes.CellRange), + context.valueTypeProvider.createCollectionValueTypeOf( + context.valueTypeProvider.Primitives.CellRange, + ), ) .map((astNode) => context.wrapperFactories.CellRange.wrap(astNode)); assert(relativeColumns.every(isColumnWrapper)); diff --git a/libs/extensions/tabular/exec/src/lib/csv-interpreter-executor.spec.ts b/libs/extensions/tabular/exec/src/lib/csv-interpreter-executor.spec.ts index 1f665d91..32613ecc 100644 --- a/libs/extensions/tabular/exec/src/lib/csv-interpreter-executor.spec.ts +++ b/libs/extensions/tabular/exec/src/lib/csv-interpreter-executor.spec.ts @@ -12,6 +12,7 @@ import { import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -37,6 +38,7 @@ describe('Validation of CSVInterpreterExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -66,13 +68,13 @@ describe('Validation of CSVInterpreterExecutor', () => { return new CSVInterpreterExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/tabular/exec/src/lib/csv-interpreter-executor.ts b/libs/extensions/tabular/exec/src/lib/csv-interpreter-executor.ts index c40b1cdf..4312ecc5 100644 --- a/libs/extensions/tabular/exec/src/lib/csv-interpreter-executor.ts +++ b/libs/extensions/tabular/exec/src/lib/csv-interpreter-executor.ts @@ -13,7 +13,7 @@ import { type TextFile, implementsStatic, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; import * as E from 'fp-ts/lib/Either'; import { type Either, isLeft } from 'fp-ts/lib/Either'; @@ -34,15 +34,15 @@ export class CSVInterpreterExecutor extends AbstractBlockExecutor< ): Promise> { const delimiter = context.getPropertyValue( 'delimiter', - PrimitiveValuetypes.Text, + context.valueTypeProvider.Primitives.Text, ); const enclosing = context.getPropertyValue( 'enclosing', - PrimitiveValuetypes.Text, + context.valueTypeProvider.Primitives.Text, ); const enclosingEscape = context.getPropertyValue( 'enclosingEscape', - PrimitiveValuetypes.Text, + context.valueTypeProvider.Primitives.Text, ); context.logger.logDebug( diff --git a/libs/extensions/tabular/exec/src/lib/row-deleter-executor.spec.ts b/libs/extensions/tabular/exec/src/lib/row-deleter-executor.spec.ts index 582d56a8..76480212 100644 --- a/libs/extensions/tabular/exec/src/lib/row-deleter-executor.spec.ts +++ b/libs/extensions/tabular/exec/src/lib/row-deleter-executor.spec.ts @@ -9,6 +9,7 @@ import { getTestExecutionContext } from '@jvalue/jayvee-execution/test'; import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -36,6 +37,7 @@ describe('Validation of RowDeleterExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -65,13 +67,13 @@ describe('Validation of RowDeleterExecutor', () => { return new RowDeleterExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/tabular/exec/src/lib/row-deleter-executor.ts b/libs/extensions/tabular/exec/src/lib/row-deleter-executor.ts index 3bda8d2f..b9996844 100644 --- a/libs/extensions/tabular/exec/src/lib/row-deleter-executor.ts +++ b/libs/extensions/tabular/exec/src/lib/row-deleter-executor.ts @@ -13,9 +13,7 @@ import { implementsStatic, } from '@jvalue/jayvee-execution'; import { - CollectionValuetype, IOType, - PrimitiveValuetypes, type RowWrapper, getRowIndex, isRowWrapper, @@ -41,7 +39,9 @@ export class RowDeleterExecutor extends AbstractBlockExecutor< const relativeRows = context .getPropertyValue( 'delete', - new CollectionValuetype(PrimitiveValuetypes.CellRange), + context.valueTypeProvider.createCollectionValueTypeOf( + context.valueTypeProvider.Primitives.CellRange, + ), ) .map((astNode) => context.wrapperFactories.CellRange.wrap(astNode)); assert(relativeRows.every(isRowWrapper)); diff --git a/libs/extensions/tabular/exec/src/lib/sheet-picker-executor.spec.ts b/libs/extensions/tabular/exec/src/lib/sheet-picker-executor.spec.ts index b751cfaa..e5c9af26 100644 --- a/libs/extensions/tabular/exec/src/lib/sheet-picker-executor.spec.ts +++ b/libs/extensions/tabular/exec/src/lib/sheet-picker-executor.spec.ts @@ -9,6 +9,7 @@ import { getTestExecutionContext } from '@jvalue/jayvee-execution/test'; import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -36,6 +37,7 @@ describe('Validation of SheetPickerExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -65,13 +67,13 @@ describe('Validation of SheetPickerExecutor', () => { return new SheetPickerExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/tabular/exec/src/lib/sheet-picker-executor.ts b/libs/extensions/tabular/exec/src/lib/sheet-picker-executor.ts index e1d92409..e5b0cdfa 100644 --- a/libs/extensions/tabular/exec/src/lib/sheet-picker-executor.ts +++ b/libs/extensions/tabular/exec/src/lib/sheet-picker-executor.ts @@ -11,7 +11,7 @@ import { type Workbook, implementsStatic, } from '@jvalue/jayvee-execution'; -import { IOType, PrimitiveValuetypes } from '@jvalue/jayvee-language-server'; +import { IOType } from '@jvalue/jayvee-language-server'; @implementsStatic() export class SheetPickerExecutor extends AbstractBlockExecutor< @@ -31,7 +31,7 @@ export class SheetPickerExecutor extends AbstractBlockExecutor< ): Promise> { const sheetName = context.getPropertyValue( 'sheetName', - PrimitiveValuetypes.Text, + context.valueTypeProvider.Primitives.Text, ); const sheet = workbook.getSheetByName(sheetName); if (sheet === undefined) { diff --git a/libs/extensions/tabular/exec/src/lib/table-interpreter-executor.spec.ts b/libs/extensions/tabular/exec/src/lib/table-interpreter-executor.spec.ts index 88e8c863..492348c4 100644 --- a/libs/extensions/tabular/exec/src/lib/table-interpreter-executor.spec.ts +++ b/libs/extensions/tabular/exec/src/lib/table-interpreter-executor.spec.ts @@ -9,6 +9,7 @@ import { getTestExecutionContext } from '@jvalue/jayvee-execution/test'; import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -36,6 +37,7 @@ describe('Validation of TableInterpreterExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -65,13 +67,13 @@ describe('Validation of TableInterpreterExecutor', () => { return new TableInterpreterExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/extensions/tabular/exec/src/lib/table-interpreter-executor.ts b/libs/extensions/tabular/exec/src/lib/table-interpreter-executor.ts index 24f59915..7942a0b9 100644 --- a/libs/extensions/tabular/exec/src/lib/table-interpreter-executor.ts +++ b/libs/extensions/tabular/exec/src/lib/table-interpreter-executor.ts @@ -17,13 +17,10 @@ import { } from '@jvalue/jayvee-execution'; import { CellIndex, - CollectionValuetype, IOType, type InternalValueRepresentation, - PrimitiveValuetypes, type ValueType, type ValuetypeAssignment, - createValueType, rowIndexToString, } from '@jvalue/jayvee-language-server'; @@ -52,11 +49,13 @@ export class TableInterpreterExecutor extends AbstractBlockExecutor< ): Promise> { const header = context.getPropertyValue( 'header', - PrimitiveValuetypes.Boolean, + context.valueTypeProvider.Primitives.Boolean, ); const columnDefinitions = context.getPropertyValue( 'columns', - new CollectionValuetype(PrimitiveValuetypes.ValuetypeAssignment), + context.valueTypeProvider.createCollectionValueTypeOf( + context.valueTypeProvider.Primitives.ValuetypeAssignment, + ), ); let columnEntries: ColumnDefinitionEntry[]; @@ -90,8 +89,10 @@ export class TableInterpreterExecutor extends AbstractBlockExecutor< }); } - columnEntries = - this.deriveColumnDefinitionEntriesWithoutHeader(columnDefinitions); + columnEntries = this.deriveColumnDefinitionEntriesWithoutHeader( + columnDefinitions, + context, + ); } const numberOfTableRows = header @@ -205,10 +206,13 @@ export class TableInterpreterExecutor extends AbstractBlockExecutor< private deriveColumnDefinitionEntriesWithoutHeader( columnDefinitions: ValuetypeAssignment[], + context: ExecutionContext, ): ColumnDefinitionEntry[] { return columnDefinitions.map( (columnDefinition, columnDefinitionIndex) => { - const columnValuetype = createValueType(columnDefinition.type); + const columnValuetype = context.wrapperFactories.ValueType.wrap( + columnDefinition.type, + ); assert(columnValuetype !== undefined); return { sheetColumnIndex: columnDefinitionIndex, @@ -238,7 +242,9 @@ export class TableInterpreterExecutor extends AbstractBlockExecutor< ); continue; } - const columnValuetype = createValueType(columnDefinition.type); + const columnValuetype = context.wrapperFactories.ValueType.wrap( + columnDefinition.type, + ); assert(columnValuetype !== undefined); columnEntries.push({ diff --git a/libs/extensions/tabular/exec/src/lib/table-transformer-executor.spec.ts b/libs/extensions/tabular/exec/src/lib/table-transformer-executor.spec.ts index df184fcd..6522ee1d 100644 --- a/libs/extensions/tabular/exec/src/lib/table-transformer-executor.spec.ts +++ b/libs/extensions/tabular/exec/src/lib/table-transformer-executor.spec.ts @@ -9,7 +9,7 @@ import { getTestExecutionContext } from '@jvalue/jayvee-execution/test'; import { type BlockDefinition, IOType, - PrimitiveValuetypes, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -40,6 +40,7 @@ describe('Validation of TableTransformerExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -51,17 +52,17 @@ describe('Validation of TableTransformerExecutor', () => { { columnName: 'index', sheetColumnIndex: 0, - valueType: PrimitiveValuetypes.Integer, + valueType: services.ValueTypeProvider.Primitives.Integer, }, { columnName: 'name', sheetColumnIndex: 1, - valueType: PrimitiveValuetypes.Text, + valueType: services.ValueTypeProvider.Primitives.Text, }, { columnName: 'flag', sheetColumnIndex: 2, - valueType: PrimitiveValuetypes.Boolean, + valueType: services.ValueTypeProvider.Primitives.Boolean, }, ]); } @@ -94,13 +95,24 @@ describe('Validation of TableTransformerExecutor', () => { return new TableTransformerExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext( + locator, + document, + services, + [block], + { + isDebugMode: false, + debugGranularity: 'minimal', + debugTargets: 'all', + }, + true, + ), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../../test/test-extension/TestBlockTypes.jv'), ]); @@ -166,7 +178,7 @@ describe('Validation of TableTransformerExecutor', () => { expect(result.right.getColumn('index')).toEqual( expect.objectContaining({ values: [false, true, true, true, true, true], - valueType: PrimitiveValuetypes.Boolean, + valueType: services.ValueTypeProvider.Primitives.Boolean, }), ); } @@ -179,7 +191,7 @@ describe('Validation of TableTransformerExecutor', () => { { columnName: 'index', sheetColumnIndex: 0, - valueType: PrimitiveValuetypes.Integer, + valueType: services.ValueTypeProvider.Primitives.Integer, }, ]); const result = await parseAndExecuteExecutor(text, testTable); diff --git a/libs/extensions/tabular/exec/src/lib/table-transformer-executor.ts b/libs/extensions/tabular/exec/src/lib/table-transformer-executor.ts index d023c250..1e7314ce 100644 --- a/libs/extensions/tabular/exec/src/lib/table-transformer-executor.ts +++ b/libs/extensions/tabular/exec/src/lib/table-transformer-executor.ts @@ -15,10 +15,8 @@ import { implementsStatic, } from '@jvalue/jayvee-execution'; import { - CollectionValuetype, IOType, type InternalValueRepresentation, - PrimitiveValuetypes, } from '@jvalue/jayvee-language-server'; @implementsStatic() @@ -39,15 +37,17 @@ export class TableTransformerExecutor extends AbstractBlockExecutor< ): Promise> { const inputColumnNames = context.getPropertyValue( 'inputColumns', - new CollectionValuetype(PrimitiveValuetypes.Text), + context.valueTypeProvider.createCollectionValueTypeOf( + context.valueTypeProvider.Primitives.Text, + ), ); const outputColumnName = context.getPropertyValue( 'outputColumn', - PrimitiveValuetypes.Text, + context.valueTypeProvider.Primitives.Text, ); const usedTransform = context.getPropertyValue( 'use', - PrimitiveValuetypes.Transform, + context.valueTypeProvider.Primitives.Transform, ); const checkInputColumnsExistResult = this.checkInputColumnsExist( @@ -59,7 +59,7 @@ export class TableTransformerExecutor extends AbstractBlockExecutor< return checkInputColumnsExistResult; } - const executor = new TransformExecutor(usedTransform); + const executor = new TransformExecutor(usedTransform, context); const transformInputDetailsList = executor.getInputDetails(); const transformOutputDetails = executor.getOutputDetails(); diff --git a/libs/extensions/tabular/exec/src/lib/xlsx-interpreter-executor.spec.ts b/libs/extensions/tabular/exec/src/lib/xlsx-interpreter-executor.spec.ts index d816424d..364c03bc 100644 --- a/libs/extensions/tabular/exec/src/lib/xlsx-interpreter-executor.spec.ts +++ b/libs/extensions/tabular/exec/src/lib/xlsx-interpreter-executor.spec.ts @@ -12,6 +12,7 @@ import { import { type BlockDefinition, IOType, + type JayveeServices, createJayveeServices, } from '@jvalue/jayvee-language-server'; import { @@ -37,6 +38,7 @@ describe('Validation of XLSXInterpreterExecutor', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -75,13 +77,13 @@ describe('Validation of XLSXInterpreterExecutor', () => { return new XLSXInterpreterExecutor().doExecute( IOInput, - getTestExecutionContext(locator, document, [block]), + getTestExecutionContext(locator, document, services, [block]), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve(__dirname, '../../test/test-extension/TestBlockTypes.jv'), ]); diff --git a/libs/interpreter-lib/src/interpreter.ts b/libs/interpreter-lib/src/interpreter.ts index a53610e2..2911d1c5 100644 --- a/libs/interpreter-lib/src/interpreter.ts +++ b/libs/interpreter-lib/src/interpreter.ts @@ -213,6 +213,7 @@ async function runPipeline( constraintExtension, loggerFactory.createLogger(), jayveeServices.WrapperFactories, + jayveeServices.ValueTypeProvider, { isDebugMode: runOptions.debug, debugGranularity: runOptions.debugGranularity, @@ -221,6 +222,7 @@ async function runPipeline( new EvaluationContext( jayveeServices.RuntimeParameterProvider, jayveeServices.operators.EvaluatorRegistry, + jayveeServices.ValueTypeProvider, ), ); 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 e4b96884..c2d82f48 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,9 +9,11 @@ import { DefaultOperatorEvaluatorRegistry, DefaultOperatorTypeComputerRegistry, EvaluationContext, + type JayveeServices, type RuntimeParameterLiteral, RuntimeParameterProvider, ValidationContext, + ValueTypeProvider, WrapperFactoryProvider, createJayveeServices, } from '@jvalue/jayvee-language-server'; @@ -39,6 +41,7 @@ describe('Validation of validateRuntimeParameterLiteral', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); @@ -68,11 +71,16 @@ describe('Validation of validateRuntimeParameterLiteral', () => { } const operatorEvaluatorRegistry = new DefaultOperatorEvaluatorRegistry(); - const operatorTypeComputerRegistry = - new DefaultOperatorTypeComputerRegistry(); + const valueTypeProvider = new ValueTypeProvider(); const wrapperFactories = new WrapperFactoryProvider( operatorEvaluatorRegistry, + valueTypeProvider, ); + const operatorTypeComputerRegistry = + new DefaultOperatorTypeComputerRegistry( + valueTypeProvider, + wrapperFactories, + ); validateRuntimeParameterLiteral(runtimeParameter, { validationContext: new ValidationContext( @@ -82,14 +90,16 @@ describe('Validation of validateRuntimeParameterLiteral', () => { evaluationContext: new EvaluationContext( runtimeProvider, operatorEvaluatorRegistry, + valueTypeProvider, ), + valueTypeProvider: valueTypeProvider, wrapperFactories: wrapperFactories, }); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await loadTestExtensions(services, [ path.resolve( diff --git a/libs/language-server/src/lib/ast/expressions/evaluation-context.ts b/libs/language-server/src/lib/ast/expressions/evaluation-context.ts index 4faba4ba..b059b260 100644 --- a/libs/language-server/src/lib/ast/expressions/evaluation-context.ts +++ b/libs/language-server/src/lib/ast/expressions/evaluation-context.ts @@ -19,7 +19,7 @@ import { isTransformPortDefinition, isValueKeywordLiteral, } from '../generated/ast'; -import { PrimitiveValuetypes } from '../wrappers/value-type/primitive/primitive-value-types'; +import { type ValueTypeProvider } from '../wrappers'; import { type ValueType } from '../wrappers/value-type/value-type'; import { type InternalValueRepresentation } from './internal-value-representation'; @@ -36,6 +36,7 @@ export class EvaluationContext { constructor( public readonly runtimeParameterProvider: RuntimeParameterProvider, public readonly operatorRegistry: OperatorEvaluatorRegistry, + public readonly valueTypeProvider: ValueTypeProvider, ) {} getValueFor( @@ -44,7 +45,7 @@ export class EvaluationContext { if (isReferenceLiteral(literal)) { return this.getValueForReference(literal); } else if (isValueKeywordLiteral(literal)) { - return this.getValueForValueKeyword(literal); + return this.getValueForValueKeyword(literal, this.valueTypeProvider); } assertUnreachable(literal); } @@ -105,6 +106,7 @@ export class EvaluationContext { getValueForValueKeyword( literal: ValueKeywordLiteral, + valueTypeProvider: ValueTypeProvider, ): InternalValueRepresentation | undefined { if (this.valueKeywordValue === undefined) { return undefined; @@ -112,7 +114,7 @@ export class EvaluationContext { if (literal.lengthAccess) { assert( - PrimitiveValuetypes.Text.isInternalValueRepresentation( + valueTypeProvider.Primitives.Text.isInternalValueRepresentation( this.valueKeywordValue, ), ); diff --git a/libs/language-server/src/lib/ast/expressions/operator-registry.ts b/libs/language-server/src/lib/ast/expressions/operator-registry.ts index 1c4c7124..fc0fc9b5 100644 --- a/libs/language-server/src/lib/ast/expressions/operator-registry.ts +++ b/libs/language-server/src/lib/ast/expressions/operator-registry.ts @@ -7,6 +7,10 @@ import { type TernaryExpression, type UnaryExpression, } from '../generated/ast'; +import { + type ValueTypeProvider, + type WrapperFactoryProvider, +} from '../wrappers'; import { AdditionOperatorEvaluator } from './evaluators/addition-operator-evaluator'; import { AndOperatorEvaluator } from './evaluators/and-operator-evaluator'; @@ -120,37 +124,45 @@ export class DefaultOperatorTypeComputerRegistry implements OperatorTypeComputerRegistry { unary = { - not: new NotOperatorTypeComputer(), - '+': new SignOperatorTypeComputer(), - '-': new SignOperatorTypeComputer(), - sqrt: new SqrtOperatorTypeComputer(), - floor: new IntegerConversionOperatorTypeComputer(), - ceil: new IntegerConversionOperatorTypeComputer(), - round: new IntegerConversionOperatorTypeComputer(), - lowercase: new StringTransformTypeComputer(), - uppercase: new StringTransformTypeComputer(), + not: new NotOperatorTypeComputer(this.valueTypeProvider), + '+': new SignOperatorTypeComputer(this.valueTypeProvider), + '-': new SignOperatorTypeComputer(this.valueTypeProvider), + sqrt: new SqrtOperatorTypeComputer(this.valueTypeProvider), + floor: new IntegerConversionOperatorTypeComputer(this.valueTypeProvider), + ceil: new IntegerConversionOperatorTypeComputer(this.valueTypeProvider), + round: new IntegerConversionOperatorTypeComputer(this.valueTypeProvider), + lowercase: new StringTransformTypeComputer(this.valueTypeProvider), + uppercase: new StringTransformTypeComputer(this.valueTypeProvider), }; binary = { - pow: new ExponentialOperatorTypeComputer(), - root: new ExponentialOperatorTypeComputer(), - '*': new BasicArithmeticOperatorTypeComputer(), - '/': new DivisionOperatorTypeComputer(), - '%': new DivisionOperatorTypeComputer(), - '+': new BasicArithmeticOperatorTypeComputer(), - '-': new BasicArithmeticOperatorTypeComputer(), - matches: new MatchesOperatorTypeComputer(), - in: new InOperatorTypeComputer(), - '<': new RelationalOperatorTypeComputer(), - '<=': new RelationalOperatorTypeComputer(), - '>': new RelationalOperatorTypeComputer(), - '>=': new RelationalOperatorTypeComputer(), - '==': new EqualityOperatorTypeComputer(), - '!=': new EqualityOperatorTypeComputer(), - xor: new LogicalOperatorTypeComputer(), - and: new LogicalOperatorTypeComputer(), - or: new LogicalOperatorTypeComputer(), + pow: new ExponentialOperatorTypeComputer(this.valueTypeProvider), + root: new ExponentialOperatorTypeComputer(this.valueTypeProvider), + '*': new BasicArithmeticOperatorTypeComputer(this.valueTypeProvider), + '/': new DivisionOperatorTypeComputer(this.valueTypeProvider), + '%': new DivisionOperatorTypeComputer(this.valueTypeProvider), + '+': new BasicArithmeticOperatorTypeComputer(this.valueTypeProvider), + '-': new BasicArithmeticOperatorTypeComputer(this.valueTypeProvider), + matches: new MatchesOperatorTypeComputer(this.valueTypeProvider), + in: new InOperatorTypeComputer( + this.valueTypeProvider, + this.wrapperFactories, + ), + '<': new RelationalOperatorTypeComputer(this.valueTypeProvider), + '<=': new RelationalOperatorTypeComputer(this.valueTypeProvider), + '>': new RelationalOperatorTypeComputer(this.valueTypeProvider), + '>=': new RelationalOperatorTypeComputer(this.valueTypeProvider), + '==': new EqualityOperatorTypeComputer(this.valueTypeProvider), + '!=': new EqualityOperatorTypeComputer(this.valueTypeProvider), + xor: new LogicalOperatorTypeComputer(this.valueTypeProvider), + and: new LogicalOperatorTypeComputer(this.valueTypeProvider), + or: new LogicalOperatorTypeComputer(this.valueTypeProvider), }; ternary = { - replace: new ReplaceOperatorTypeComputer(), + replace: new ReplaceOperatorTypeComputer(this.valueTypeProvider), }; + + constructor( + private readonly valueTypeProvider: ValueTypeProvider, + private readonly wrapperFactories: WrapperFactoryProvider, + ) {} } diff --git a/libs/language-server/src/lib/ast/expressions/test-utils.ts b/libs/language-server/src/lib/ast/expressions/test-utils.ts index c7e2d1c0..bc6eff62 100644 --- a/libs/language-server/src/lib/ast/expressions/test-utils.ts +++ b/libs/language-server/src/lib/ast/expressions/test-utils.ts @@ -6,14 +6,11 @@ import { NodeFileSystem } from 'langium/node'; import { parseHelper } from '../../../test/langium-utils'; import { createJayveeServices } from '../../jayvee-module'; -import { RuntimeParameterProvider } from '../../services'; import { type TransformDefinition } from '../generated/ast'; -import { WrapperFactoryProvider } from '../wrappers'; import { evaluateExpression } from './evaluate-expression'; import { EvaluationContext } from './evaluation-context'; import { type InternalValueRepresentation } from './internal-value-representation'; -import { DefaultOperatorEvaluatorRegistry } from './operator-registry'; export async function executeDefaultTextToTextExpression( expression: string, @@ -53,11 +50,10 @@ export async function executeExpressionTestHelper( 'transforms@0', ) as TransformDefinition; - const runTimeParameterProvider = new RuntimeParameterProvider(); - const operatorEvaluatorRegistry = new DefaultOperatorEvaluatorRegistry(); const evaluationContext = new EvaluationContext( - runTimeParameterProvider, - new DefaultOperatorEvaluatorRegistry(), + services.RuntimeParameterProvider, + services.operators.EvaluatorRegistry, + services.ValueTypeProvider, ); evaluationContext.setValueForReference(inputValueName, inputValueValue); @@ -66,6 +62,6 @@ export async function executeExpressionTestHelper( // eslint-disable-next-line @typescript-eslint/no-non-null-assertion transform.body.outputAssignments[0]!.expression, evaluationContext, - new WrapperFactoryProvider(operatorEvaluatorRegistry), + services.WrapperFactories, ); } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/basic-arithmetic-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/basic-arithmetic-operator-type-computer.ts index f7aad404..50da9b55 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/basic-arithmetic-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/basic-arithmetic-operator-type-computer.ts @@ -2,13 +2,18 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultBinaryOperatorTypeComputer } from '../operator-type-computer'; export class BasicArithmeticOperatorTypeComputer extends DefaultBinaryOperatorTypeComputer { - constructor() { - super(PrimitiveValuetypes.Decimal, PrimitiveValuetypes.Decimal); + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + super( + valueTypeProvider.Primitives.Decimal, + valueTypeProvider.Primitives.Decimal, + ); } override doComputeType( @@ -16,11 +21,11 @@ export class BasicArithmeticOperatorTypeComputer extends DefaultBinaryOperatorTy rightOperandType: ValueType, ): ValueType { if ( - leftOperandType === PrimitiveValuetypes.Integer && - rightOperandType === PrimitiveValuetypes.Integer + leftOperandType === this.valueTypeProvider.Primitives.Integer && + rightOperandType === this.valueTypeProvider.Primitives.Integer ) { - return PrimitiveValuetypes.Integer; + return this.valueTypeProvider.Primitives.Integer; } - return PrimitiveValuetypes.Decimal; + return this.valueTypeProvider.Primitives.Decimal; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/division-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/division-operator-type-computer.ts index cd0d803e..556b8797 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/division-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/division-operator-type-computer.ts @@ -2,16 +2,21 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultBinaryOperatorTypeComputer } from '../operator-type-computer'; export class DivisionOperatorTypeComputer extends DefaultBinaryOperatorTypeComputer { - constructor() { - super(PrimitiveValuetypes.Decimal, PrimitiveValuetypes.Decimal); + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + super( + valueTypeProvider.Primitives.Decimal, + valueTypeProvider.Primitives.Decimal, + ); } override doComputeType(): ValueType { - return PrimitiveValuetypes.Decimal; + return this.valueTypeProvider.Primitives.Decimal; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/equality-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/equality-operator-type-computer.ts index e05fdb75..b185d960 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/equality-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/equality-operator-type-computer.ts @@ -4,19 +4,25 @@ import { type ValidationContext } from '../../../validation/validation-context'; import { type BinaryExpression } from '../../generated/ast'; -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { type BinaryOperatorTypeComputer } from '../operator-type-computer'; export class EqualityOperatorTypeComputer implements BinaryOperatorTypeComputer { - private readonly ALLOWED_OPERAND_TYPES: ValueType[] = [ - PrimitiveValuetypes.Boolean, - PrimitiveValuetypes.Text, - PrimitiveValuetypes.Integer, - PrimitiveValuetypes.Decimal, - ]; + private readonly ALLOWED_OPERAND_TYPES: ValueType[]; + + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + this.ALLOWED_OPERAND_TYPES = [ + valueTypeProvider.Primitives.Boolean, + valueTypeProvider.Primitives.Text, + valueTypeProvider.Primitives.Integer, + valueTypeProvider.Primitives.Decimal, + ]; + } computeType( leftOperandType: ValueType, @@ -62,6 +68,6 @@ export class EqualityOperatorTypeComputer return undefined; } - return PrimitiveValuetypes.Boolean; + return this.valueTypeProvider.Primitives.Boolean; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/exponential-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/exponential-operator-type-computer.ts index 0fdb822e..f840fe8f 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/exponential-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/exponential-operator-type-computer.ts @@ -2,16 +2,21 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultBinaryOperatorTypeComputer } from '../operator-type-computer'; export class ExponentialOperatorTypeComputer extends DefaultBinaryOperatorTypeComputer { - constructor() { - super(PrimitiveValuetypes.Decimal, PrimitiveValuetypes.Decimal); + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + super( + valueTypeProvider.Primitives.Decimal, + valueTypeProvider.Primitives.Decimal, + ); } protected override doComputeType(): ValueType { - return PrimitiveValuetypes.Decimal; + return this.valueTypeProvider.Primitives.Decimal; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/in-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/in-operator-type-computer.ts index bbacd550..5b3b726c 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/in-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/in-operator-type-computer.ts @@ -6,22 +6,32 @@ import { strict as assert } from 'assert'; import { type ValidationContext } from '../../../validation/validation-context'; import { type BinaryExpression } from '../../generated/ast'; +import { type WrapperFactoryProvider } from '../../wrappers'; import { - CollectionValuetype, + type CollectionValueType, type ValueType, - isCollectionValuetype, + type ValueTypeProvider, + isCollectionValueType, } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; import { type BinaryOperatorTypeComputer } from '../operator-type-computer'; export class InOperatorTypeComputer implements BinaryOperatorTypeComputer { - private readonly ALLOWED_LEFT_OPERAND_TYPES: ValueType[] = [ - PrimitiveValuetypes.Text, - PrimitiveValuetypes.Integer, - PrimitiveValuetypes.Decimal, - ]; - private readonly ALLOWED_RIGHT_OPERAND_TYPES: CollectionValuetype[] = - this.ALLOWED_LEFT_OPERAND_TYPES.map((v) => new CollectionValuetype(v)); + private readonly ALLOWED_LEFT_OPERAND_TYPES: ValueType[]; + private readonly ALLOWED_RIGHT_OPERAND_TYPES: CollectionValueType[]; + + constructor( + protected readonly valueTypeProvider: ValueTypeProvider, + protected readonly wrapperFactories: WrapperFactoryProvider, + ) { + this.ALLOWED_LEFT_OPERAND_TYPES = [ + valueTypeProvider.Primitives.Text, + valueTypeProvider.Primitives.Integer, + valueTypeProvider.Primitives.Decimal, + ]; + this.ALLOWED_RIGHT_OPERAND_TYPES = this.ALLOWED_LEFT_OPERAND_TYPES.map( + (v) => valueTypeProvider.createCollectionValueTypeOf(v), + ); + } computeType( leftOperandType: ValueType, @@ -56,9 +66,18 @@ export class InOperatorTypeComputer implements BinaryOperatorTypeComputer { return undefined; } assert( - isCollectionValuetype(rightOperandType, PrimitiveValuetypes.Decimal) || - isCollectionValuetype(rightOperandType, PrimitiveValuetypes.Integer) || - isCollectionValuetype(rightOperandType, PrimitiveValuetypes.Text), + isCollectionValueType( + rightOperandType, + this.valueTypeProvider.Primitives.Decimal, + ) || + isCollectionValueType( + rightOperandType, + this.valueTypeProvider.Primitives.Integer, + ) || + isCollectionValueType( + rightOperandType, + this.valueTypeProvider.Primitives.Text, + ), ); // allow 3 in [3.5, 5.3] @@ -79,6 +98,6 @@ export class InOperatorTypeComputer implements BinaryOperatorTypeComputer { return undefined; } - return PrimitiveValuetypes.Boolean; + return this.valueTypeProvider.Primitives.Boolean; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/integer-conversion-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/integer-conversion-operator-type-computer.ts index 7503993b..dffe6438 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/integer-conversion-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/integer-conversion-operator-type-computer.ts @@ -2,16 +2,18 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultUnaryOperatorTypeComputer } from '../operator-type-computer'; export class IntegerConversionOperatorTypeComputer extends DefaultUnaryOperatorTypeComputer { - constructor() { - super(PrimitiveValuetypes.Decimal); + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + super(valueTypeProvider.Primitives.Decimal); } override doComputeType(): ValueType { - return PrimitiveValuetypes.Integer; + return this.valueTypeProvider.Primitives.Integer; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/logical-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/logical-operator-type-computer.ts index d19bb553..eed1e5a1 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/logical-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/logical-operator-type-computer.ts @@ -2,16 +2,21 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultBinaryOperatorTypeComputer } from '../operator-type-computer'; export class LogicalOperatorTypeComputer extends DefaultBinaryOperatorTypeComputer { - constructor() { - super(PrimitiveValuetypes.Boolean, PrimitiveValuetypes.Boolean); + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + super( + valueTypeProvider.Primitives.Boolean, + valueTypeProvider.Primitives.Boolean, + ); } protected override doComputeType(): ValueType { - return PrimitiveValuetypes.Boolean; + return this.valueTypeProvider.Primitives.Boolean; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/matches-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/matches-operator-type-computer.ts index 800c5522..2780b05e 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/matches-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/matches-operator-type-computer.ts @@ -2,16 +2,21 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultBinaryOperatorTypeComputer } from '../operator-type-computer'; export class MatchesOperatorTypeComputer extends DefaultBinaryOperatorTypeComputer { - constructor() { - super(PrimitiveValuetypes.Text, PrimitiveValuetypes.Regex); + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + super( + valueTypeProvider.Primitives.Text, + valueTypeProvider.Primitives.Regex, + ); } override doComputeType(): ValueType { - return PrimitiveValuetypes.Boolean; + return this.valueTypeProvider.Primitives.Boolean; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/not-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/not-operator-type-computer.ts index a7dcab04..543946dc 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/not-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/not-operator-type-computer.ts @@ -2,16 +2,18 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultUnaryOperatorTypeComputer } from '../operator-type-computer'; export class NotOperatorTypeComputer extends DefaultUnaryOperatorTypeComputer { - constructor() { - super(PrimitiveValuetypes.Boolean); + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + super(valueTypeProvider.Primitives.Boolean); } override doComputeType(): ValueType { - return PrimitiveValuetypes.Boolean; + return this.valueTypeProvider.Primitives.Boolean; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/relational-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/relational-operator-type-computer.ts index 012d3a52..18ae68bc 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/relational-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/relational-operator-type-computer.ts @@ -2,16 +2,21 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultBinaryOperatorTypeComputer } from '../operator-type-computer'; export class RelationalOperatorTypeComputer extends DefaultBinaryOperatorTypeComputer { - constructor() { - super(PrimitiveValuetypes.Decimal, PrimitiveValuetypes.Decimal); + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + super( + valueTypeProvider.Primitives.Decimal, + valueTypeProvider.Primitives.Decimal, + ); } override doComputeType(): ValueType { - return PrimitiveValuetypes.Boolean; + return this.valueTypeProvider.Primitives.Boolean; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/replace-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/replace-operator-type-computer.ts index 221459b2..d6c3584b 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/replace-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/replace-operator-type-computer.ts @@ -2,20 +2,22 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultTernaryOperatorTypeComputer } from '../operator-type-computer'; export class ReplaceOperatorTypeComputer extends DefaultTernaryOperatorTypeComputer { - constructor() { + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { super( - PrimitiveValuetypes.Text, - PrimitiveValuetypes.Regex, - PrimitiveValuetypes.Text, + valueTypeProvider.Primitives.Text, + valueTypeProvider.Primitives.Regex, + valueTypeProvider.Primitives.Text, ); } override doComputeType(): ValueType { - return PrimitiveValuetypes.Text; + return this.valueTypeProvider.Primitives.Text; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/sign-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/sign-operator-type-computer.ts index 60986040..b6e16cd5 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/sign-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/sign-operator-type-computer.ts @@ -2,13 +2,15 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultUnaryOperatorTypeComputer } from '../operator-type-computer'; export class SignOperatorTypeComputer extends DefaultUnaryOperatorTypeComputer { - constructor() { - super(PrimitiveValuetypes.Decimal); + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + super(valueTypeProvider.Primitives.Decimal); } override doComputeType(operandType: ValueType): ValueType { diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/sqrt-operator-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/sqrt-operator-type-computer.ts index ee54beea..ac913254 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/sqrt-operator-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/sqrt-operator-type-computer.ts @@ -2,16 +2,18 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultUnaryOperatorTypeComputer } from '../operator-type-computer'; export class SqrtOperatorTypeComputer extends DefaultUnaryOperatorTypeComputer { - constructor() { - super(PrimitiveValuetypes.Decimal); + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + super(valueTypeProvider.Primitives.Decimal); } override doComputeType(): ValueType { - return PrimitiveValuetypes.Decimal; + return this.valueTypeProvider.Primitives.Decimal; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-computers/string-transform-type-computer.ts b/libs/language-server/src/lib/ast/expressions/type-computers/string-transform-type-computer.ts index 37eb0ce7..e27aa696 100644 --- a/libs/language-server/src/lib/ast/expressions/type-computers/string-transform-type-computer.ts +++ b/libs/language-server/src/lib/ast/expressions/type-computers/string-transform-type-computer.ts @@ -2,16 +2,18 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { type ValueType } from '../../wrappers/value-type'; -import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types'; +import { + type ValueType, + type ValueTypeProvider, +} from '../../wrappers/value-type'; import { DefaultUnaryOperatorTypeComputer } from '../operator-type-computer'; export class StringTransformTypeComputer extends DefaultUnaryOperatorTypeComputer { - constructor() { - super(PrimitiveValuetypes.Text); + constructor(protected readonly valueTypeProvider: ValueTypeProvider) { + super(valueTypeProvider.Primitives.Text); } override doComputeType(): ValueType { - return PrimitiveValuetypes.Text; + return this.valueTypeProvider.Primitives.Text; } } diff --git a/libs/language-server/src/lib/ast/expressions/type-inference.ts b/libs/language-server/src/lib/ast/expressions/type-inference.ts index ab59f626..7e699ac1 100644 --- a/libs/language-server/src/lib/ast/expressions/type-inference.ts +++ b/libs/language-server/src/lib/ast/expressions/type-inference.ts @@ -38,33 +38,40 @@ import { import { getNextAstNodeContainer } from '../model-util'; // eslint-disable-next-line import/no-cycle import { - type AtomicValuetype, - CollectionValuetype, + type AtomicValueType, type PrimitiveValueType, - isAtomicValuetype, + type ValueType, + type ValueTypeProvider, + type WrapperFactoryProvider, + isAtomicValueType, isPrimitiveValueType, } from '../wrappers'; -import { EmptyCollection } from '../wrappers/value-type/primitive/collection/empty-collection-value-type'; -import { PrimitiveValuetypes } from '../wrappers/value-type/primitive/primitive-value-types'; -import { type ValueType } from '../wrappers/value-type/value-type'; -import { createValueType } from '../wrappers/value-type/value-type-util'; import { isEveryValueDefined } from './typeguards'; export function inferExpressionType( expression: Expression | undefined, validationContext: ValidationContext, + valueTypeProvider: ValueTypeProvider, + wrapperFactories: WrapperFactoryProvider, ): ValueType | undefined { if (expression === undefined) { return undefined; } if (isExpressionLiteral(expression)) { - return inferTypeFromExpressionLiteral(expression, validationContext); + return inferTypeFromExpressionLiteral( + expression, + validationContext, + valueTypeProvider, + wrapperFactories, + ); } if (isUnaryExpression(expression)) { const innerType = inferExpressionType( expression.expression, validationContext, + valueTypeProvider, + wrapperFactories, ); if (innerType === undefined) { return undefined; @@ -75,8 +82,18 @@ export function inferExpressionType( return typeComputer.computeType(innerType, expression, validationContext); } if (isBinaryExpression(expression)) { - const leftType = inferExpressionType(expression.left, validationContext); - const rightType = inferExpressionType(expression.right, validationContext); + const leftType = inferExpressionType( + expression.left, + validationContext, + valueTypeProvider, + wrapperFactories, + ); + const rightType = inferExpressionType( + expression.right, + validationContext, + valueTypeProvider, + wrapperFactories, + ); if (leftType === undefined || rightType === undefined) { return undefined; } @@ -92,12 +109,24 @@ export function inferExpressionType( ); } if (isTernaryExpression(expression)) { - const firstType = inferExpressionType(expression.first, validationContext); + const firstType = inferExpressionType( + expression.first, + validationContext, + valueTypeProvider, + wrapperFactories, + ); const secondType = inferExpressionType( expression.second, validationContext, + valueTypeProvider, + wrapperFactories, + ); + const thirdType = inferExpressionType( + expression.third, + validationContext, + valueTypeProvider, + wrapperFactories, ); - const thirdType = inferExpressionType(expression.third, validationContext); if ( firstType === undefined || secondType === undefined || @@ -126,29 +155,45 @@ export function inferExpressionType( function inferTypeFromExpressionLiteral( expression: ExpressionLiteral, validationContext: ValidationContext, + valueTypeProvider: ValueTypeProvider, + wrapperFactories: WrapperFactoryProvider, ): ValueType | undefined { if (isValueLiteral(expression)) { if (isTextLiteral(expression)) { - return PrimitiveValuetypes.Text; + return valueTypeProvider.Primitives.Text; } else if (isBooleanLiteral(expression)) { - return PrimitiveValuetypes.Boolean; + return valueTypeProvider.Primitives.Boolean; } else if (isNumericLiteral(expression)) { - return inferNumericType(expression); + return inferNumericType(expression, valueTypeProvider); } else if (isCellRangeLiteral(expression)) { - return PrimitiveValuetypes.CellRange; + return valueTypeProvider.Primitives.CellRange; } else if (isRegexLiteral(expression)) { - return PrimitiveValuetypes.Regex; + return valueTypeProvider.Primitives.Regex; } else if (isValuetypeAssignmentLiteral(expression)) { - return PrimitiveValuetypes.ValuetypeAssignment; + return valueTypeProvider.Primitives.ValuetypeAssignment; } else if (isCollectionLiteral(expression)) { - return inferCollectionType(expression, validationContext); + return inferCollectionType( + expression, + validationContext, + valueTypeProvider, + wrapperFactories, + ); } assertUnreachable(expression); } else if (isFreeVariableLiteral(expression)) { if (isValueKeywordLiteral(expression)) { - return inferTypeFromValueKeyword(expression, validationContext); + return inferTypeFromValueKeyword( + expression, + validationContext, + valueTypeProvider, + wrapperFactories, + ); } else if (isReferenceLiteral(expression)) { - return inferTypeFromReferenceLiteral(expression); + return inferTypeFromReferenceLiteral( + expression, + valueTypeProvider, + wrapperFactories, + ); } assertUnreachable(expression); } @@ -160,20 +205,27 @@ function inferTypeFromExpressionLiteral( * Thus, the inferred type might differ from the literal type. * E.g., 3.0 is currently interpreted as integer but is a DecimalLiteral. */ -function inferNumericType(expression: NumericLiteral): ValueType { +function inferNumericType( + expression: NumericLiteral, + valueTypeProvider: ValueTypeProvider, +): ValueType { if (Number.isInteger(expression.value)) { - return PrimitiveValuetypes.Integer; + return valueTypeProvider.Primitives.Integer; } - return PrimitiveValuetypes.Decimal; + return valueTypeProvider.Primitives.Decimal; } function inferCollectionType( collection: CollectionLiteral, validationContext: ValidationContext, + valueTypeProvider: ValueTypeProvider, + wrapperFactories: WrapperFactoryProvider, ): ValueType | undefined { const elementValuetypes = inferCollectionElementTypes( collection, validationContext, + valueTypeProvider, + wrapperFactories, ); if (elementValuetypes === undefined) { return undefined; @@ -182,14 +234,14 @@ function inferCollectionType( const stacks = elementValuetypes.map(getValuetypeHierarchyStack); if (stacks.length === 0) { - return EmptyCollection; + return valueTypeProvider.EmptyCollection; } if (stacks.length === 1) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const stack = stacks[0]!; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const resultingInnerType = stack[stack.length - 1]!; - return new CollectionValuetype(resultingInnerType); + return valueTypeProvider.createCollectionValueTypeOf(resultingInnerType); } const primitiveValuetypes = stacks.map((stack) => stack[0]); @@ -208,19 +260,28 @@ function inferCollectionType( return undefined; } - const commonAtomicValuetype = pickCommonAtomicValuetype(stacks); - if (commonAtomicValuetype === undefined) { - return new CollectionValuetype(commonPrimitiveValuetype); + const commonAtomicValueType = pickCommonAtomicValueType(stacks); + if (commonAtomicValueType === undefined) { + return valueTypeProvider.createCollectionValueTypeOf( + commonPrimitiveValuetype, + ); } - return new CollectionValuetype(commonAtomicValuetype); + return valueTypeProvider.createCollectionValueTypeOf(commonAtomicValueType); } function inferCollectionElementTypes( collection: CollectionLiteral, validationContext: ValidationContext, + valueTypeProvider: ValueTypeProvider, + wrapperFactories: WrapperFactoryProvider, ): ValueType[] | undefined { const elementValuetypes = collection.values.map((value) => - inferExpressionType(value, validationContext), + inferExpressionType( + value, + validationContext, + valueTypeProvider, + wrapperFactories, + ), ); if (!isEveryValueDefined(elementValuetypes)) { return undefined; @@ -228,14 +289,14 @@ function inferCollectionElementTypes( return elementValuetypes; } -type ValuetypeHierarchyStack = [PrimitiveValueType, ...AtomicValuetype[]]; +type ValuetypeHierarchyStack = [PrimitiveValueType, ...AtomicValueType[]]; function getValuetypeHierarchyStack( valueType: ValueType, ): ValuetypeHierarchyStack { if (isPrimitiveValueType(valueType)) { return [valueType]; - } else if (isAtomicValuetype(valueType)) { + } else if (isAtomicValueType(valueType)) { const supertype = valueType.getSupertype(); assert(supertype !== undefined); return [...getValuetypeHierarchyStack(supertype), valueType]; @@ -271,17 +332,19 @@ function pickCommonPrimitiveValuetype( return resultingType; } -function pickCommonAtomicValuetype( +function pickCommonAtomicValueType( stacks: ValuetypeHierarchyStack[], -): ValueType | undefined { +): PrimitiveValueType | AtomicValueType | undefined { const minimumStackLength = Math.min(...stacks.map((stack) => stack.length)); - let resultingType: ValueType | undefined = undefined; + let resultingType: PrimitiveValueType | AtomicValueType | undefined = + undefined; for (let stackLevel = 1; stackLevel < minimumStackLength; ++stackLevel) { - const typesOfCurrentLevel: ValueType[] = stacks.map( - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - (stack) => stack[stackLevel]!, - ); + const typesOfCurrentLevel: (PrimitiveValueType | AtomicValueType)[] = + stacks.map( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + (stack) => stack[stackLevel]!, + ); if (!areAllTypesEqual(typesOfCurrentLevel)) { // Return the common value type of the previous level @@ -308,6 +371,8 @@ function areAllTypesEqual(types: ValueType[]): boolean { function inferTypeFromValueKeyword( expression: ValueKeywordLiteral, validationContext: ValidationContext, + valueTypeProvider: ValueTypeProvider, + wrapperFactories: WrapperFactoryProvider, ): ValueType | undefined { const expressionConstraintContainer = getNextAstNodeContainer( expression, @@ -324,14 +389,16 @@ function inferTypeFromValueKeyword( return undefined; } - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - const valueType = createValueType(expressionConstraintContainer?.valueType); + const valueType = wrapperFactories.ValueType.wrap( + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + expressionConstraintContainer?.valueType, + ); if (valueType === undefined) { return undefined; } if (expression.lengthAccess) { - if (!valueType.isConvertibleTo(PrimitiveValuetypes.Text)) { + if (!valueType.isConvertibleTo(valueTypeProvider.Primitives.Text)) { validationContext.accept( 'error', 'The length can only be accessed from text values ', @@ -342,13 +409,15 @@ function inferTypeFromValueKeyword( ); return undefined; } - return PrimitiveValuetypes.Integer; + return valueTypeProvider.Primitives.Integer; } return valueType; } function inferTypeFromReferenceLiteral( expression: ReferenceLiteral, + valueTypeProvider: ValueTypeProvider, + wrapperFactories: WrapperFactoryProvider, ): ValueType | undefined { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition const referenced = expression?.value?.ref; @@ -357,10 +426,10 @@ function inferTypeFromReferenceLiteral( } if (isConstraintDefinition(referenced)) { - return PrimitiveValuetypes.Constraint; + return valueTypeProvider.Primitives.Constraint; } if (isTransformDefinition(referenced)) { - return PrimitiveValuetypes.Transform; + return valueTypeProvider.Primitives.Transform; } if ( isTransformPortDefinition(referenced) || @@ -371,7 +440,7 @@ function inferTypeFromReferenceLiteral( if (valueType === undefined) { return undefined; } - return createValueType(valueType); + return wrapperFactories.ValueType.wrap(valueType); } assertUnreachable(referenced); } diff --git a/libs/language-server/src/lib/ast/wrappers/index.ts b/libs/language-server/src/lib/ast/wrappers/index.ts index 2e137e12..0c12ce60 100644 --- a/libs/language-server/src/lib/ast/wrappers/index.ts +++ b/libs/language-server/src/lib/ast/wrappers/index.ts @@ -2,9 +2,10 @@ // // SPDX-License-Identifier: AGPL-3.0-only -export * from './value-type'; - -/* Note: Only export types if possible to enforce usage of WrapperFactory outside this directory */ +/* + * Note: Only export types if possible to enforce usage of WrapperFactory outside this directory. + * This allows us to avoid dependency cycles between the language server and interpreter. + */ export { type AstNodeWrapper } from './ast-node-wrapper'; export { @@ -22,5 +23,7 @@ export { type CompositeBlockTypeWrapper } from './typed-object/composite-block-t export { type ConstraintTypeWrapper } from './typed-object/constrainttype-wrapper'; export * from './typed-object/typed-object-wrapper'; +export * from './value-type'; // type export handled one level deeper + export * from './util'; export * from './wrapper-factory-provider'; diff --git a/libs/language-server/src/lib/ast/wrappers/typed-object/block-type-wrapper.ts b/libs/language-server/src/lib/ast/wrappers/typed-object/block-type-wrapper.ts index 23b468c7..3e29090b 100644 --- a/libs/language-server/src/lib/ast/wrappers/typed-object/block-type-wrapper.ts +++ b/libs/language-server/src/lib/ast/wrappers/typed-object/block-type-wrapper.ts @@ -15,7 +15,7 @@ import { } from '../../expressions'; import { type ReferenceableBlockTypeDefinition } from '../../generated/ast'; import { IOType, getIOType } from '../../io-type'; -import { createValueType } from '../value-type'; +import { type ValueTypeProvider } from '../value-type'; import { type WrapperFactoryProvider } from '../wrapper-factory-provider'; import { @@ -46,6 +46,7 @@ export class BlockTypeWrapper extends TypedObjectWrapper, operatorEvaluatorRegistry: OperatorEvaluatorRegistry, + valueTypeProvider: ValueTypeProvider, wrapperFactories: WrapperFactoryProvider, ) { const blockTypeDefinition = isReference(toBeWrapped) @@ -57,7 +58,7 @@ export class BlockTypeWrapper extends TypedObjectWrapper = {}; for (const property of blockTypeDefinition.properties) { - const valueType = createValueType(property.valueType); + const valueType = wrapperFactories.ValueType.wrap(property.valueType); assert(valueType !== undefined); properties[property.name] = { @@ -69,6 +70,7 @@ export class BlockTypeWrapper extends TypedObjectWrapper, operatorEvaluatorRegistry: OperatorEvaluatorRegistry, + valueTypeProvider: ValueTypeProvider, wrapperFactories: WrapperFactoryProvider, ) { const constraintTypeDefinition = isReference(toBeWrapped) @@ -51,7 +52,7 @@ export class ConstraintTypeWrapper extends TypedObjectWrapper = {}; for (const property of constraintTypeDefinition.properties) { - const valueType = createValueType(property.valueType); + const valueType = wrapperFactories.ValueType.wrap(property.valueType); assert(valueType !== undefined); properties[property.name] = { @@ -63,6 +64,7 @@ export class ConstraintTypeWrapper extends TypedObjectWrapper implements AstNodeWrapper { - constructor(public readonly astNode: ValuetypeDefinition) { + constructor( + public readonly astNode: ValuetypeDefinition, + private readonly valueTypeProvider: ValueTypeProvider, + private readonly wrapperFactories: WrapperFactoryProvider, + ) { super(); } acceptVisitor(visitor: ValueTypeVisitor): R { - return visitor.visitAtomicValuetype(this); + return visitor.visitAtomicValueType(this); } - getConstraints( - context: EvaluationContext, - wrapperFactories: WrapperFactoryProvider, - ): ConstraintDefinition[] { + getConstraints(context: EvaluationContext): ConstraintDefinition[] { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition const constraintCollection = this.astNode?.constraints; assert(constraintCollection !== undefined); - const constraintCollectionType = new CollectionValuetype( - PrimitiveValuetypes.Constraint, + const constraintCollectionType = new CollectionValueType( + this.valueTypeProvider.Primitives.Constraint, ); const constraints = - evaluateExpression(constraintCollection, context, wrapperFactories) ?? []; + evaluateExpression( + constraintCollection, + context, + this.wrapperFactories, + ) ?? []; if (!constraintCollectionType.isInternalValueRepresentation(constraints)) { return []; } @@ -91,7 +94,7 @@ export class AtomicValueType protected override doGetSupertype(): ValueType | undefined { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition const supertype = this.astNode?.type; - return createValueType(supertype); + return this.wrapperFactories.ValueType.wrap(supertype); } override isInternalValueRepresentation( @@ -112,6 +115,6 @@ export class AtomicValueType } } -export function isAtomicValuetype(v: unknown): v is AtomicValueType { +export function isAtomicValueType(v: unknown): v is AtomicValueType { return v instanceof AtomicValueType; } diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/index.ts b/libs/language-server/src/lib/ast/wrappers/value-type/index.ts index 1b05638f..d5f70003 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/index.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/index.ts @@ -2,10 +2,11 @@ // // SPDX-License-Identifier: AGPL-3.0-only -export * from './value-type'; -export { - type AtomicValueType as AtomicValuetype, - isAtomicValuetype, -} from './atomic-value-type'; -export * from './primitive'; -export * from './value-type-util'; +/* + * Note: Only export types if possible to enforce usage of WrapperFactory outside this directory. + * This allows us to avoid dependency cycles between the language server and interpreter. + */ + +export { type ValueType, ValueTypeVisitor } from './value-type'; +export { type AtomicValueType, isAtomicValueType } from './atomic-value-type'; +export * from './primitive'; // type export handled one level deeper diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/boolean-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/boolean-value-type.ts index d3be78c3..063c280f 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/boolean-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/boolean-value-type.ts @@ -7,7 +7,7 @@ import { type ValueTypeVisitor } from '../value-type'; import { PrimitiveValueType } from './primitive-value-type'; -class BooleanValuetypeImpl extends PrimitiveValueType { +export class BooleanValuetype extends PrimitiveValueType { acceptVisitor(visitor: ValueTypeVisitor): R { return visitor.visitBoolean(this); } @@ -37,13 +37,3 @@ Examples: true, false `.trim(); } } - -// Only export instance to enforce singleton -export const Boolean = new BooleanValuetypeImpl(); - -// Only export type to allow narrowing down in visitors -export type BooleanValuetype = InstanceType; - -export function isBooleanValuetype(v: unknown): v is BooleanValuetype { - return v === Boolean; -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/cell-range-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/cell-range-value-type.ts index 465759a9..fbd9f42b 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/cell-range-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/cell-range-value-type.ts @@ -11,7 +11,7 @@ import { type ValueTypeVisitor } from '../value-type'; import { PrimitiveValueType } from './primitive-value-type'; -class CellRangeValuetypeImpl extends PrimitiveValueType { +export class CellRangeValuetype extends PrimitiveValueType { acceptVisitor(visitor: ValueTypeVisitor): R { return visitor.visitCellRange(this); } @@ -30,13 +30,3 @@ class CellRangeValuetypeImpl extends PrimitiveValueType { return isCellRangeLiteral(operandValue); } } - -// Only export instance to enforce singleton -export const CellRange = new CellRangeValuetypeImpl(); - -// Only export type to allow narrowing down in visitors -export type CellRangeValuetype = InstanceType; - -export function isCellRangeValuetype(v: unknown): v is CellRangeValuetype { - return v === CellRange; -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/collection-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/collection-value-type.ts index 0962b3a3..23a04a47 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/collection-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/collection-value-type.ts @@ -2,16 +2,11 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { strict as assert } from 'assert'; - import { type AtomicInternalValueRepresentation, type InternalValueRepresentation, } from '../../../../expressions/internal-value-representation'; -import { type ValueTypeReference } from '../../../../generated/ast'; import { type ValueType, type ValueTypeVisitor } from '../../value-type'; -// eslint-disable-next-line import/no-cycle -import { createValueType } from '../../value-type-util'; import { AbstractCollectionValueType, @@ -57,26 +52,3 @@ export function isCollectionValueType< >(v: unknown, elementType: ValueType): v is CollectionValueType { return v instanceof CollectionValueType && v.elementType.equals(elementType); } - -export function createCollectionValueType( - collectionRef: ValueTypeReference, -): CollectionValueType { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - const collectionDefinition = collectionRef?.reference?.ref; - assert(collectionDefinition?.name === 'Collection'); - const collectionGenerics = collectionRef.genericRefs; - if (collectionGenerics.length !== 1) { - throw new Error( - "Valuetype Collection needs exactly one generic parameter to define its elements' type", - ); - } - const generic = collectionGenerics[0]; - assert(generic !== undefined); - const elementValuetype = createValueType(generic.ref); - if (elementValuetype === undefined) { - throw new Error( - "Could not create value type for the elements' type of value type Collection", - ); - } - return new CollectionValueType(elementValuetype); -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/empty-collection-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/empty-collection-value-type.ts index 961d57b2..1c388b11 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/empty-collection-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/empty-collection-value-type.ts @@ -6,10 +6,9 @@ import { type InternalValueRepresentation } from '../../../../expressions/intern import { type ValueType, type ValueTypeVisitor } from '../../value-type'; import { AbstractCollectionValueType } from './abstract-collection-value-type'; -// eslint-disable-next-line import/no-cycle import { CollectionValueType } from './collection-value-type'; -class EmptyCollectionValueTypeImpl extends AbstractCollectionValueType { +export class EmptyCollectionValueType extends AbstractCollectionValueType { override isConvertibleTo(target: ValueType): boolean { return ( super.isConvertibleTo(target) || target instanceof CollectionValueType @@ -30,17 +29,3 @@ class EmptyCollectionValueTypeImpl extends AbstractCollectionValueType; - -export function isEmptyCollectionValueType( - v: unknown, -): v is EmptyCollectionValueType { - return v === EmptyCollection; -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/index.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/index.ts index a3ae5433..4c1d7f6a 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/index.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/collection/index.ts @@ -2,13 +2,13 @@ // // SPDX-License-Identifier: AGPL-3.0-only -// eslint-disable-next-line import/no-cycle -export { - CollectionValueType as CollectionValuetype, - isCollectionValueType as isCollectionValuetype, -} from './collection-value-type'; +/* + * Note: Only export types if possible to enforce usage of WrapperFactory outside this directory. + * This allows us to avoid dependency cycles between the language server and interpreter. + */ export { - type EmptyCollectionValueType as EmptyCollectionValuetype, - isEmptyCollectionValueType as isEmptyCollectionValuetype, -} from './empty-collection-value-type'; + type CollectionValueType, + isCollectionValueType, +} from './collection-value-type'; +export { type EmptyCollectionValueType } from './empty-collection-value-type'; diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/constraint-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/constraint-value-type.ts index 458754a5..943d73a7 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/constraint-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/constraint-value-type.ts @@ -11,7 +11,7 @@ import { type ValueTypeVisitor } from '../value-type'; import { PrimitiveValueType } from './primitive-value-type'; -class ConstraintValuetypeImpl extends PrimitiveValueType { +export class ConstraintValuetype extends PrimitiveValueType { acceptVisitor(visitor: ValueTypeVisitor): R { return visitor.visitConstraint(this); } @@ -30,13 +30,3 @@ class ConstraintValuetypeImpl extends PrimitiveValueType { return isConstraintDefinition(operandValue); } } - -// Only export instance to enforce singleton -export const Constraint = new ConstraintValuetypeImpl(); - -// Only export type to allow narrowing down in visitors -export type ConstraintValuetype = InstanceType; - -export function isConstraintValuetype(v: unknown): v is ConstraintValuetype { - return v === Constraint; -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/decimal-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/decimal-value-type.ts index ec6125d1..c79bc14f 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/decimal-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/decimal-value-type.ts @@ -7,7 +7,7 @@ import { type ValueTypeVisitor } from '../value-type'; import { PrimitiveValueType } from './primitive-value-type'; -class DecimalValuetypeImpl extends PrimitiveValueType { +export class DecimalValuetype extends PrimitiveValueType { acceptVisitor(visitor: ValueTypeVisitor): R { return visitor.visitDecimal(this); } @@ -37,13 +37,3 @@ Example: 3.14 `.trim(); } } - -// Only export instance to enforce singleton -export const Decimal = new DecimalValuetypeImpl(); - -// Only export type to allow narrowing down in visitors -export type DecimalValuetype = InstanceType; - -export function isDecimalValuetype(v: unknown): v is DecimalValuetype { - return v === Decimal; -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/index.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/index.ts index 6a4b4e95..c0158b62 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/index.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/index.ts @@ -2,39 +2,29 @@ // // SPDX-License-Identifier: AGPL-3.0-only -// eslint-disable-next-line import/no-cycle -export * from './collection'; +/* + * Note: Only export types if possible to enforce usage of WrapperFactory outside this directory. + * This allows us to avoid dependency cycles between the language server and interpreter. + */ -export * from './primitive-value-type'; -export * from './primitive-value-types'; - -export { - type BooleanValuetype, - isBooleanValuetype, -} from './boolean-value-type'; -export { - type CellRangeValuetype, - isCellRangeValuetype, -} from './cell-range-value-type'; -export { - type ConstraintValuetype, - isConstraintValuetype, -} from './constraint-value-type'; -export { - type DecimalValuetype, - isDecimalValuetype, -} from './decimal-value-type'; export { - type IntegerValuetype, - isIntegerValuetype, -} from './integer-value-type'; -export { type RegexValuetype, isRegexValuetype } from './regex-value-type'; -export { type TextValuetype, isTextValuetype } from './text-value-type'; -export { - type ValuetypeAssignmentValuetype, - isValuetypeAssignmentValuetype, -} from './value-type-assignment-value-type'; + isPrimitiveValueType, + type PrimitiveValueType, +} from './primitive-value-type'; + +export { type BooleanValuetype } from './boolean-value-type'; +export { type CellRangeValuetype } from './cell-range-value-type'; +export { type ConstraintValuetype } from './constraint-value-type'; +export { type DecimalValuetype } from './decimal-value-type'; +export { type IntegerValuetype } from './integer-value-type'; +export { type RegexValuetype } from './regex-value-type'; +export { type TextValuetype } from './text-value-type'; +export { type ValuetypeAssignmentValuetype } from './value-type-assignment-value-type'; +export { type TransformValuetype } from './transform-value-type'; + export { - type TransformValuetype, - isTransformValuetype, -} from './transform-value-type'; + ValueTypeProvider, + PrimitiveValueTypeProvider, +} from './primitive-value-type-provider'; + +export * from './collection'; // type export handled one level deeper diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/integer-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/integer-value-type.ts index 4c32a620..b4f9eecc 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/integer-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/integer-value-type.ts @@ -5,12 +5,12 @@ import { type InternalValueRepresentation } from '../../../expressions/internal-value-representation'; import { type ValueType, type ValueTypeVisitor } from '../value-type'; -import { Decimal } from './decimal-value-type'; +import { DecimalValuetype } from './decimal-value-type'; import { PrimitiveValueType } from './primitive-value-type'; -class IntegerValuetypeImpl extends PrimitiveValueType { +export class IntegerValuetype extends PrimitiveValueType { override isConvertibleTo(target: ValueType): boolean { - return super.isConvertibleTo(target) || target === Decimal; + return super.isConvertibleTo(target) || target instanceof DecimalValuetype; } acceptVisitor(visitor: ValueTypeVisitor): R { @@ -42,13 +42,3 @@ Example: 3 `.trim(); } } - -// Only export instance to enforce singleton -export const Integer = new IntegerValuetypeImpl(); - -// Only export type to allow narrowing down in visitors -export type IntegerValuetype = InstanceType; - -export function isIntegerValuetype(v: unknown): v is IntegerValuetype { - return v === Integer; -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/primitive-value-type-provider.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/primitive-value-type-provider.ts new file mode 100644 index 00000000..651e2578 --- /dev/null +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/primitive-value-type-provider.ts @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +import { type InternalValueRepresentation } from '../../../expressions'; +import { type ValueType } from '../value-type'; + +import { BooleanValuetype } from './boolean-value-type'; +import { CellRangeValuetype } from './cell-range-value-type'; +import { CollectionValueType } from './collection/collection-value-type'; +import { EmptyCollectionValueType } from './collection/empty-collection-value-type'; +import { ConstraintValuetype } from './constraint-value-type'; +import { DecimalValuetype } from './decimal-value-type'; +import { IntegerValuetype } from './integer-value-type'; +import { type PrimitiveValueType } from './primitive-value-type'; +import { RegexValuetype } from './regex-value-type'; +import { TextValuetype } from './text-value-type'; +import { TransformValuetype } from './transform-value-type'; +import { ValuetypeAssignmentValuetype } from './value-type-assignment-value-type'; + +/** + * Should be created as singleton due to the equality comparison of primitive value types. + * Exported for testing purposes. + */ +export class ValueTypeProvider { + Primitives = new PrimitiveValueTypeProvider(); + EmptyCollection = new EmptyCollectionValueType(); + + createCollectionValueTypeOf( + input: ValueType, + ): CollectionValueType { + return new CollectionValueType(input); + } +} + +export class PrimitiveValueTypeProvider { + Decimal = new DecimalValuetype(); + Boolean = new BooleanValuetype(); + Integer = new IntegerValuetype(); + Text = new TextValuetype(); + + Regex = new RegexValuetype(); + CellRange = new CellRangeValuetype(); + Constraint = new ConstraintValuetype(); + ValuetypeAssignment = new ValuetypeAssignmentValuetype(); + + Transform = new TransformValuetype(); + + getAll(): PrimitiveValueType[] { + return [ + this.Boolean, + this.Decimal, + this.Integer, + this.Text, + this.Regex, + this.CellRange, + this.Constraint, + this.ValuetypeAssignment, + this.Transform, + ]; + } +} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/primitive-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/primitive-value-type.ts index 4cc46d79..c2b171e2 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/primitive-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/primitive-value-type.ts @@ -13,7 +13,7 @@ export abstract class PrimitiveValueType< } override isConvertibleTo(target: ValueType): boolean { - return target.equals(this); + return target.equals(this); // Primitive value types are always singletons } override equals(target: ValueType): boolean { diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/primitive-value-types.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/primitive-value-types.ts deleted file mode 100644 index 2ea87063..00000000 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/primitive-value-types.ts +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { strict as assert } from 'assert'; - -import { type ValuetypeDefinition } from '../../../generated/ast'; - -import { Boolean, type BooleanValuetype } from './boolean-value-type'; -import { CellRange, type CellRangeValuetype } from './cell-range-value-type'; -import { Constraint, type ConstraintValuetype } from './constraint-value-type'; -import { Decimal, type DecimalValuetype } from './decimal-value-type'; -import { Integer, type IntegerValuetype } from './integer-value-type'; -import { type PrimitiveValueType } from './primitive-value-type'; -import { Regex, type RegexValuetype } from './regex-value-type'; -import { Text, type TextValuetype } from './text-value-type'; -import { Transform, type TransformValuetype } from './transform-value-type'; -import { - ValuetypeAssignment, - type ValuetypeAssignmentValuetype, -} from './value-type-assignment-value-type'; - -export const PrimitiveValuetypes: { - Boolean: BooleanValuetype; - Decimal: DecimalValuetype; - Integer: IntegerValuetype; - Text: TextValuetype; - Regex: RegexValuetype; - CellRange: CellRangeValuetype; - Constraint: ConstraintValuetype; - ValuetypeAssignment: ValuetypeAssignmentValuetype; - Transform: TransformValuetype; -} = { - Boolean: Boolean, - Decimal: Decimal, - Integer: Integer, - Text: Text, - - Regex: Regex, - CellRange: CellRange, - Constraint: Constraint, - ValuetypeAssignment: ValuetypeAssignment, - - Transform: Transform, -}; - -export function createPrimitiveValuetype( - builtinValuetype: ValuetypeDefinition, -): PrimitiveValueType | undefined { - assert(builtinValuetype.isBuiltin); - const name = builtinValuetype.name; - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (name === undefined) { - return undefined; - } - - const matchingPrimitives = Object.values(PrimitiveValuetypes).filter( - (valueType) => valueType.getName() === name, - ); - if (matchingPrimitives.length === 0) { - throw new Error( - `Found no PrimitiveValuetype for builtin value type "${name}"`, - ); - } - if (matchingPrimitives.length > 1) { - throw new Error( - `Found multiple ambiguous PrimitiveValuetype for builtin value type "${name}"`, - ); - } - return matchingPrimitives[0]; -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/regex-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/regex-value-type.ts index 25862763..02723cd6 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/regex-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/regex-value-type.ts @@ -7,7 +7,7 @@ import { type ValueTypeVisitor } from '../value-type'; import { PrimitiveValueType } from './primitive-value-type'; -class RegexValuetypeImpl extends PrimitiveValueType { +export class RegexValuetype extends PrimitiveValueType { acceptVisitor(visitor: ValueTypeVisitor): R { return visitor.visitRegex(this); } @@ -26,13 +26,3 @@ class RegexValuetypeImpl extends PrimitiveValueType { return operandValue instanceof RegExp; } } - -// Only export instance to enforce singleton -export const Regex = new RegexValuetypeImpl(); - -// Only export type to allow narrowing down in visitors -export type RegexValuetype = InstanceType; - -export function isRegexValuetype(v: unknown): v is RegexValuetype { - return v === Regex; -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/text-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/text-value-type.ts index e8e386cf..bc5fdf47 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/text-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/text-value-type.ts @@ -7,7 +7,7 @@ import { type ValueTypeVisitor } from '../value-type'; import { PrimitiveValueType } from './primitive-value-type'; -class TextValuetypeImpl extends PrimitiveValueType { +export class TextValuetype extends PrimitiveValueType { acceptVisitor(visitor: ValueTypeVisitor): R { return visitor.visitText(this); } @@ -37,13 +37,3 @@ Example: "Hello World" `.trim(); } } - -// Only export instance to enforce singleton -export const Text = new TextValuetypeImpl(); - -// Only export type to allow narrowing down in visitors -export type TextValuetype = InstanceType; - -export function isTextValuetype(v: unknown): v is TextValuetype { - return v === Text; -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/transform-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/transform-value-type.ts index 1f036d22..5ade797a 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/transform-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/transform-value-type.ts @@ -11,7 +11,7 @@ import { type ValueTypeVisitor } from '../value-type'; import { PrimitiveValueType } from './primitive-value-type'; -class TransformValuetypeImpl extends PrimitiveValueType { +export class TransformValuetype extends PrimitiveValueType { acceptVisitor(visitor: ValueTypeVisitor): R { return visitor.visitTransform(this); } @@ -30,13 +30,3 @@ class TransformValuetypeImpl extends PrimitiveValueType { return isTransformDefinition(operandValue); } } - -// Only export instance to enforce singleton -export const Transform = new TransformValuetypeImpl(); - -// Only export type to allow narrowing down in visitors -export type TransformValuetype = InstanceType; - -export function isTransformValuetype(v: unknown): v is TransformValuetype { - return v === Transform; -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/value-type-assignment-value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/value-type-assignment-value-type.ts index f69a365a..07d6c3c0 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/primitive/value-type-assignment-value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/primitive/value-type-assignment-value-type.ts @@ -11,7 +11,7 @@ import { type ValueTypeVisitor } from '../value-type'; import { PrimitiveValueType } from './primitive-value-type'; -class ValuetypeAssignmentValuetypeImpl extends PrimitiveValueType { +export class ValuetypeAssignmentValuetype extends PrimitiveValueType { acceptVisitor(visitor: ValueTypeVisitor): R { return visitor.visitValuetypeAssignment(this); } @@ -30,17 +30,3 @@ class ValuetypeAssignmentValuetypeImpl extends PrimitiveValueType; - -export function isValuetypeAssignmentValuetype( - v: unknown, -): v is ValuetypeAssignmentValuetype { - return v === ValuetypeAssignment; -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/value-type-util.ts b/libs/language-server/src/lib/ast/wrappers/value-type/value-type-util.ts deleted file mode 100644 index c127d1ae..00000000 --- a/libs/language-server/src/lib/ast/wrappers/value-type/value-type-util.ts +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg -// -// SPDX-License-Identifier: AGPL-3.0-only - -import { assertUnreachable } from 'langium'; - -import { - type ValueTypeReference, - type ValuetypeDefinition, - isValueTypeReference, - isValuetypeDefinition, -} from '../../generated/ast'; - -// eslint-disable-next-line import/no-cycle -import { AtomicValueType } from './atomic-value-type'; -// eslint-disable-next-line import/no-cycle -import { createPrimitiveValuetype } from './primitive'; -import { createCollectionValueType } from './primitive/collection/collection-value-type'; -import { type ValueType } from './value-type'; - -/** - * Returns the matching value type instance for a given value type keyword or definition. - * @returns the desired value type instance or undefined in case of incomplete AST nodes or a cycle in the hierarchy. - */ -export function createValueType( - identifier: ValuetypeDefinition | ValueTypeReference | undefined, -): ValueType | undefined { - if (identifier === undefined) { - return undefined; - } else if (isValueTypeReference(identifier)) { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - const valueTypeDefinition = identifier?.reference?.ref; - if (valueTypeDefinition?.name === 'Collection') { - return createCollectionValueType(identifier); - } - return createValueType(valueTypeDefinition); - } else if (isValuetypeDefinition(identifier)) { - if (identifier.name === 'Collection') { - // We don't have an object representing a generic collection - return; - } - if (identifier.isBuiltin) { - return createPrimitiveValuetype(identifier); - } - return new AtomicValueType(identifier); - } - assertUnreachable(identifier); -} diff --git a/libs/language-server/src/lib/ast/wrappers/value-type/value-type.ts b/libs/language-server/src/lib/ast/wrappers/value-type/value-type.ts index 6ef5d1ac..3b964394 100644 --- a/libs/language-server/src/lib/ast/wrappers/value-type/value-type.ts +++ b/libs/language-server/src/lib/ast/wrappers/value-type/value-type.ts @@ -9,10 +9,10 @@ import { type AtomicValueType } from './atomic-value-type'; import { type BooleanValuetype, type CellRangeValuetype, - type CollectionValuetype, + type CollectionValueType, type ConstraintValuetype, type DecimalValuetype, - type EmptyCollectionValuetype, + type EmptyCollectionValueType, type IntegerValuetype, type RegexValuetype, type TextValuetype, @@ -147,9 +147,9 @@ export abstract class ValueTypeVisitor { abstract visitConstraint(valueType: ConstraintValuetype): R; abstract visitValuetypeAssignment(valueType: ValuetypeAssignmentValuetype): R; abstract visitCollection( - valueType: CollectionValuetype | EmptyCollectionValuetype, + valueType: CollectionValueType | EmptyCollectionValueType, ): R; abstract visitTransform(valueType: TransformValuetype): R; - abstract visitAtomicValuetype(valueType: AtomicValueType): R; + abstract visitAtomicValueType(valueType: AtomicValueType): R; } diff --git a/libs/language-server/src/lib/ast/wrappers/wrapper-factory-provider.ts b/libs/language-server/src/lib/ast/wrappers/wrapper-factory-provider.ts index 96c276ee..3dcf6457 100644 --- a/libs/language-server/src/lib/ast/wrappers/wrapper-factory-provider.ts +++ b/libs/language-server/src/lib/ast/wrappers/wrapper-factory-provider.ts @@ -20,8 +20,12 @@ import { type PipeDefinition, type PipelineDefinition, type ReferenceableBlockTypeDefinition, + type ValueTypeReference, + type ValuetypeDefinition, isBuiltinConstrainttypeDefinition, isReferenceableBlockTypeDefinition, + isValueTypeReference, + isValuetypeDefinition, } from '../generated/ast'; import { type AstNodeWrapper } from './ast-node-wrapper'; @@ -31,6 +35,10 @@ import { PipelineWrapper } from './pipeline-wrapper'; // eslint-disable-next-line import/no-cycle import { BlockTypeWrapper } from './typed-object/block-type-wrapper'; import { ConstraintTypeWrapper } from './typed-object/constrainttype-wrapper'; +import { type PrimitiveValueType, type ValueType } from './value-type'; +import { AtomicValueType } from './value-type/atomic-value-type'; +import { CollectionValueType } from './value-type/primitive/collection/collection-value-type'; +import { type ValueTypeProvider } from './value-type/primitive/primitive-value-type-provider'; abstract class AstNodeWrapperFactory< N extends AstNode, @@ -66,17 +74,21 @@ export class WrapperFactoryProvider { readonly Pipe: PipeWrapperFactory; readonly CellRange: CellRangeWrapperFactory; readonly TypedObject: TypedObjectWrapperFactory; + readonly ValueType: ValueTypeWrapperFactory; constructor( private readonly operatorEvaluatorRegistry: OperatorEvaluatorRegistry, + private readonly primitiveValueTypeContainer: ValueTypeProvider, ) { this.CellRange = new CellRangeWrapperFactory(); this.BlockType = new BlockTypeWrapperFactory( this.operatorEvaluatorRegistry, + primitiveValueTypeContainer, this, ); this.ConstraintType = new ConstraintTypeWrapperFactory( this.operatorEvaluatorRegistry, + primitiveValueTypeContainer, this, ); this.Pipe = new PipeWrapperFactory(); @@ -85,6 +97,10 @@ export class WrapperFactoryProvider { this.BlockType, this.ConstraintType, ); + this.ValueType = new ValueTypeWrapperFactory( + this, + primitiveValueTypeContainer, + ); } } @@ -106,6 +122,7 @@ class BlockTypeWrapperFactory extends AstNodeWrapperFactory< > { constructor( private readonly operatorEvaluatorRegistry: OperatorEvaluatorRegistry, + private readonly valueTypeProvider: ValueTypeProvider, private readonly wrapperFactories: WrapperFactoryProvider, ) { super(); @@ -126,6 +143,7 @@ class BlockTypeWrapperFactory extends AstNodeWrapperFactory< return new BlockTypeWrapper( toBeWrapped, this.operatorEvaluatorRegistry, + this.valueTypeProvider, this.wrapperFactories, ); } @@ -137,6 +155,7 @@ class ConstraintTypeWrapperFactory extends AstNodeWrapperFactory< > { constructor( private readonly operatorEvaluatorRegistry: OperatorEvaluatorRegistry, + private readonly valueTypeProvider: ValueTypeProvider, private readonly wrapperFactories: WrapperFactoryProvider, ) { super(); @@ -157,6 +176,7 @@ class ConstraintTypeWrapperFactory extends AstNodeWrapperFactory< return new ConstraintTypeWrapper( toBeWrapped, this.operatorEvaluatorRegistry, + this.valueTypeProvider, this.wrapperFactories, ); } @@ -292,3 +312,87 @@ class TypedObjectWrapperFactory { assertUnreachable(type); } } + +class ValueTypeWrapperFactory { + constructor( + private readonly wrapperFactories: WrapperFactoryProvider, + private readonly primitiveValueTypeProvider: ValueTypeProvider, + ) {} + + wrap( + identifier: ValuetypeDefinition | ValueTypeReference | undefined, + ): ValueType | undefined { + if (identifier === undefined) { + return undefined; + } else if (isValueTypeReference(identifier)) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + const valueTypeDefinition = identifier?.reference?.ref; + if (valueTypeDefinition?.name === 'Collection') { + return this.wrapCollection(identifier); + } + return this.wrap(valueTypeDefinition); + } else if (isValuetypeDefinition(identifier)) { + if (identifier.name === 'Collection') { + // We don't have an object representing a generic collection + return; + } + if (identifier.isBuiltin) { + return this.wrapPrimitive(identifier); + } + return new AtomicValueType( + identifier, + this.primitiveValueTypeProvider, + this.wrapperFactories, + ); + } + assertUnreachable(identifier); + } + + wrapCollection(collectionRef: ValueTypeReference): CollectionValueType { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + const collectionDefinition = collectionRef?.reference?.ref; + assert(collectionDefinition?.name === 'Collection'); + const collectionGenerics = collectionRef.genericRefs; + if (collectionGenerics.length !== 1) { + throw new Error( + "Valuetype Collection needs exactly one generic parameter to define its elements' type", + ); + } + const generic = collectionGenerics[0]; + assert(generic !== undefined); + const elementValuetype = this.wrap(generic.ref); + if (elementValuetype === undefined) { + throw new Error( + "Could not create value type for the elements' type of value type Collection", + ); + } + return new CollectionValueType(elementValuetype); + } + + wrapPrimitive( + builtinValuetype: ValuetypeDefinition, + ): PrimitiveValueType | undefined { + assert(builtinValuetype.isBuiltin); + const name = builtinValuetype.name; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (name === undefined) { + return undefined; + } + + const matchingPrimitives = + this.primitiveValueTypeProvider.Primitives.getAll().filter( + (valueType) => valueType.getName() === name, + ); + if (matchingPrimitives.length === 0) { + throw new Error( + `Found no PrimitiveValuetype for builtin value type "${name}"`, + ); + } + if (matchingPrimitives.length > 1) { + throw new Error( + `Found multiple ambiguous PrimitiveValuetype for builtin value type "${name}"`, + ); + } + return matchingPrimitives[0]; + } +} diff --git a/libs/language-server/src/lib/builtin-library/stdlib.ts b/libs/language-server/src/lib/builtin-library/stdlib.ts index 91fac982..ccbfd14c 100644 --- a/libs/language-server/src/lib/builtin-library/stdlib.ts +++ b/libs/language-server/src/lib/builtin-library/stdlib.ts @@ -3,14 +3,13 @@ // SPDX-License-Identifier: AGPL-3.0-only import { IOType, type PrimitiveValueType } from '../ast'; -import { PrimitiveValuetypes } from '../ast/wrappers/value-type/primitive/primitive-value-types'; +import { ValueTypeProvider } from '../ast/wrappers/value-type/primitive/primitive-value-type-provider'; import { PartialStdLib } from './generated/partial-stdlib'; export function getBuiltinValuetypesLib() { - const primitiveValuetypes = Object.values(PrimitiveValuetypes).map( - parseBuiltinValuetypeToJayvee, - ); + const primitiveValuetypes = new ValueTypeProvider().Primitives.getAll() // instantiation is okay here as it has no side effects: it is only parsed to string + .map(parseBuiltinValuetypeToJayvee); const collectionValuetype = `${parseAsComment('For internal use only.')} builtin valuetype Collection;`; 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 2a42c277..077b09f6 100644 --- a/libs/language-server/src/lib/completion/jayvee-completion-provider.ts +++ b/libs/language-server/src/lib/completion/jayvee-completion-provider.ts @@ -15,11 +15,7 @@ import { } from 'langium'; import { CompletionItemKind } from 'vscode-languageserver'; -import { - type TypedObjectWrapper, - type WrapperFactoryProvider, - createValueType, -} from '../ast'; +import { type TypedObjectWrapper, type WrapperFactoryProvider } from '../ast'; import { type BlockDefinition, type ConstraintDefinition, @@ -150,7 +146,8 @@ export class JayveeCompletionProvider extends DefaultCompletionProvider { throw new Error('Expected parsed document to be a JayveeModel'); } parsedDocument.valueTypes.forEach((valueTypeDefinition) => { - const valueType = createValueType(valueTypeDefinition); + const valueType = + this.wrapperFactories.ValueType.wrap(valueTypeDefinition); if (valueType !== undefined && valueType.isReferenceableByUser()) { acceptor(context, { label: valueTypeDefinition.name, diff --git a/libs/language-server/src/lib/docs/jayvee-doc-generator.ts b/libs/language-server/src/lib/docs/jayvee-doc-generator.ts index c02c0dc9..06c6cb44 100644 --- a/libs/language-server/src/lib/docs/jayvee-doc-generator.ts +++ b/libs/language-server/src/lib/docs/jayvee-doc-generator.ts @@ -14,7 +14,7 @@ export interface JayveeConstraintTypeDocGenerator { } export interface JayveeValueTypesDocGenerator { - generateValueTypesDoc(valueTypes: Record): string; + generateValueTypesDoc(valueTypes: ValueType[]): string; } export interface JayveePropertyDocGenerator { diff --git a/libs/language-server/src/lib/jayvee-module.ts b/libs/language-server/src/lib/jayvee-module.ts index ad30b338..da6fb10c 100644 --- a/libs/language-server/src/lib/jayvee-module.ts +++ b/libs/language-server/src/lib/jayvee-module.ts @@ -24,6 +24,7 @@ import { JayveeGeneratedModule, JayveeGeneratedSharedModule, } from './ast/generated/module'; +import { ValueTypeProvider } from './ast/wrappers/value-type/primitive/primitive-value-type-provider'; import { WrapperFactoryProvider } from './ast/wrappers/wrapper-factory-provider'; import { JayveeWorkspaceManager } from './builtin-library/jayvee-workspace-manager'; import { JayveeCompletionProvider } from './completion/jayvee-completion-provider'; @@ -42,6 +43,7 @@ export interface JayveeAddedServices { TypeComputerRegistry: OperatorTypeComputerRegistry; EvaluatorRegistry: OperatorEvaluatorRegistry; }; + ValueTypeProvider: ValueTypeProvider; WrapperFactories: WrapperFactoryProvider; validation: { ValidationRegistry: JayveeValidationRegistry; @@ -79,11 +81,19 @@ export const JayveeModule: Module< }, RuntimeParameterProvider: () => new RuntimeParameterProvider(), operators: { - TypeComputerRegistry: () => new DefaultOperatorTypeComputerRegistry(), + TypeComputerRegistry: (services) => + new DefaultOperatorTypeComputerRegistry( + services.ValueTypeProvider, + services.WrapperFactories, + ), EvaluatorRegistry: () => new DefaultOperatorEvaluatorRegistry(), }, + ValueTypeProvider: () => new ValueTypeProvider(), WrapperFactories: (services) => - new WrapperFactoryProvider(services.operators.EvaluatorRegistry), + new WrapperFactoryProvider( + services.operators.EvaluatorRegistry, + services.ValueTypeProvider, + ), }; export const JayveeSharedModule: Module< diff --git a/libs/language-server/src/lib/validation/checks/block-type-definition.spec.ts b/libs/language-server/src/lib/validation/checks/block-type-definition.spec.ts index c8e34f41..53a34823 100644 --- a/libs/language-server/src/lib/validation/checks/block-type-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/block-type-definition.spec.ts @@ -9,7 +9,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type BuiltinBlockTypeDefinition, createJayveeServices } from '../..'; +import { + type BuiltinBlockTypeDefinition, + type JayveeServices, + createJayveeServices, +} from '../..'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation of BuiltinBlockTypeDefinition', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -47,13 +52,13 @@ describe('Validation of BuiltinBlockTypeDefinition', () => { validateBlockTypeDefinition( blockType, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/language-server/src/lib/validation/checks/block-type-definition.ts b/libs/language-server/src/lib/validation/checks/block-type-definition.ts index d42e72bb..83ff0fdf 100644 --- a/libs/language-server/src/lib/validation/checks/block-type-definition.ts +++ b/libs/language-server/src/lib/validation/checks/block-type-definition.ts @@ -7,7 +7,6 @@ import { strict as assert } from 'assert'; import { type BlockTypeProperty, type ReferenceableBlockTypeDefinition, - createValueType, evaluateExpression, } from '../../ast'; import { type JayveeValidationProps } from '../validation-registry'; @@ -183,7 +182,9 @@ function checkPropertyDefaultValuesHasCorrectType( return; } - const expectedValuetype = createValueType(property.valueType); + const expectedValuetype = props.wrapperFactories.ValueType.wrap( + property.valueType, + ); assert(expectedValuetype !== undefined); if (!expectedValuetype.isInternalValueRepresentation(evaluatedExpression)) { diff --git a/libs/language-server/src/lib/validation/checks/block-type-specific/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/block-type-specific/property-assignment.spec.ts index f2b5a2ab..d7825734 100644 --- a/libs/language-server/src/lib/validation/checks/block-type-specific/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/block-type-specific/property-assignment.spec.ts @@ -10,6 +10,7 @@ import { import { NodeFileSystem } from 'langium/node'; import { + type JayveeServices, type PropertyBody, type PropertySpecification, type TypedObjectWrapper, @@ -35,6 +36,7 @@ describe('Validation of block type specific properties', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -50,7 +52,7 @@ describe('Validation of block type specific properties', () => { 'pipelines@0/blocks@0/body', ) as PropertyBody; - const props = createJayveeValidationProps(validationAcceptorMock); + const props = createJayveeValidationProps(validationAcceptorMock, services); const wrapper = props.wrapperFactories.TypedObject.wrap( propertyBody.$container.type, ); @@ -72,7 +74,7 @@ describe('Validation of block type specific properties', () => { beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/language-server/src/lib/validation/checks/block-type-specific/property-assignment.ts b/libs/language-server/src/lib/validation/checks/block-type-specific/property-assignment.ts index 5147ff74..5872fcd8 100644 --- a/libs/language-server/src/lib/validation/checks/block-type-specific/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/block-type-specific/property-assignment.ts @@ -3,9 +3,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { - CollectionValuetype, type InternalValueRepresentation, - PrimitiveValuetypes, type PropertyAssignment, type PropertySpecification, evaluatePropertyValue, @@ -112,7 +110,7 @@ function checkCellWriterProperty( property, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.CellRange, + props.valueTypeProvider.Primitives.CellRange, ); if (cellRange === undefined) { return; @@ -145,7 +143,9 @@ function checkColumnDeleterProperty( property, props.evaluationContext, props.wrapperFactories, - new CollectionValuetype(PrimitiveValuetypes.CellRange), + props.valueTypeProvider.createCollectionValueTypeOf( + props.valueTypeProvider.Primitives.CellRange, + ), ); cellRanges?.forEach((cellRange) => { @@ -267,7 +267,9 @@ function checkRowDeleterProperty( property, props.evaluationContext, props.wrapperFactories, - new CollectionValuetype(PrimitiveValuetypes.CellRange), + props.valueTypeProvider.createCollectionValueTypeOf( + props.valueTypeProvider.Primitives.CellRange, + ), ); cellRanges?.forEach((cellRange) => { @@ -299,7 +301,9 @@ function checkTableInterpreterProperty( property, props.evaluationContext, props.wrapperFactories, - new CollectionValuetype(PrimitiveValuetypes.ValuetypeAssignment), + props.valueTypeProvider.createCollectionValueTypeOf( + props.valueTypeProvider.Primitives.ValuetypeAssignment, + ), ); if (valueTypeAssignments === undefined) { return; @@ -352,7 +356,9 @@ function checkTextLineDeleterProperty( property, props.evaluationContext, props.wrapperFactories, - new CollectionValuetype(PrimitiveValuetypes.Integer), + props.valueTypeProvider.createCollectionValueTypeOf( + props.valueTypeProvider.Primitives.Integer, + ), ); lines?.forEach((value, index) => { if (value < minTextLineIndex) { diff --git a/libs/language-server/src/lib/validation/checks/block-type-specific/property-body.spec.ts b/libs/language-server/src/lib/validation/checks/block-type-specific/property-body.spec.ts index d995d83d..497fb477 100644 --- a/libs/language-server/src/lib/validation/checks/block-type-specific/property-body.spec.ts +++ b/libs/language-server/src/lib/validation/checks/block-type-specific/property-body.spec.ts @@ -9,7 +9,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type PropertyBody, createJayveeServices } from '../../..'; +import { + type JayveeServices, + type PropertyBody, + createJayveeServices, +} from '../../..'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation of block type specific property bodies', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -45,7 +50,7 @@ describe('Validation of block type specific property bodies', () => { 'pipelines@0/blocks@0/body', ) as PropertyBody; - const props = createJayveeValidationProps(validationAcceptorMock); + const props = createJayveeValidationProps(validationAcceptorMock, services); const wrapper = props.wrapperFactories.TypedObject.wrap( propertyBody.$container.type, @@ -57,7 +62,7 @@ describe('Validation of block type specific property bodies', () => { beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/language-server/src/lib/validation/checks/block-type-specific/property-body.ts b/libs/language-server/src/lib/validation/checks/block-type-specific/property-body.ts index f96be3d2..fbc07f6c 100644 --- a/libs/language-server/src/lib/validation/checks/block-type-specific/property-body.ts +++ b/libs/language-server/src/lib/validation/checks/block-type-specific/property-body.ts @@ -2,12 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { - CollectionValuetype, - PrimitiveValuetypes, - type PropertyBody, - evaluatePropertyValue, -} from '../../../ast'; +import { type PropertyBody, evaluatePropertyValue } from '../../../ast'; import { type JayveeValidationProps } from '../../validation-registry'; export function checkBlockTypeSpecificPropertyBody( @@ -44,13 +39,13 @@ function checkTextRangeSelectorPropertyBody( lineFromProperty, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.Integer, + props.valueTypeProvider.Primitives.Integer, ); const lineTo = evaluatePropertyValue( lineToProperty, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.Integer, + props.valueTypeProvider.Primitives.Integer, ); if (lineFrom === undefined || lineTo === undefined) { return; @@ -82,14 +77,16 @@ function checkCellWriterPropertyBody( writeProperty, props.evaluationContext, props.wrapperFactories, - new CollectionValuetype(PrimitiveValuetypes.Text), + props.valueTypeProvider.createCollectionValueTypeOf( + props.valueTypeProvider.Primitives.Text, + ), ); const atValue = evaluatePropertyValue( atProperty, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.CellRange, + props.valueTypeProvider.Primitives.CellRange, ); if (writeValues === undefined || atValue === undefined) { @@ -139,13 +136,15 @@ function checkInputColumnsMatchTransformationPorts( useProperty, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.Transform, + props.valueTypeProvider.Primitives.Transform, ); const inputColumns = evaluatePropertyValue( inputColumnsProperty, props.evaluationContext, props.wrapperFactories, - new CollectionValuetype(PrimitiveValuetypes.Text), + props.valueTypeProvider.createCollectionValueTypeOf( + props.valueTypeProvider.Primitives.Text, + ), ); if (transform === undefined || inputColumns === undefined) { 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 97e57ae6..fc503f60 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,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type ColumnId, createJayveeServices } from '../../../lib'; +import { + type ColumnId, + type JayveeServices, + createJayveeServices, +} from '../../../lib'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation of ColumnId', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -47,13 +52,13 @@ describe('Validation of ColumnId', () => { validateColumnId( columnId, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/language-server/src/lib/validation/checks/composite-block-type-definition.spec.ts b/libs/language-server/src/lib/validation/checks/composite-block-type-definition.spec.ts index 1a7a8d5b..eb932e5c 100644 --- a/libs/language-server/src/lib/validation/checks/composite-block-type-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/composite-block-type-definition.spec.ts @@ -9,7 +9,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type CompositeBlockTypeDefinition, createJayveeServices } from '../..'; +import { + type CompositeBlockTypeDefinition, + type JayveeServices, + createJayveeServices, +} from '../..'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation of CompositeBlockTypeDefinition', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -47,13 +52,13 @@ describe('Validation of CompositeBlockTypeDefinition', () => { validateCompositeBlockTypeDefinition( blockType, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-assignment.spec.ts b/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-assignment.spec.ts index 8f6a86c5..cae4851b 100644 --- a/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-assignment.spec.ts +++ b/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-assignment.spec.ts @@ -10,6 +10,7 @@ import { import { NodeFileSystem } from 'langium/node'; import { + type JayveeServices, type PropertyBody, type PropertySpecification, type TypedObjectWrapper, @@ -35,6 +36,7 @@ describe('Validation of constraint type specific properties', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -50,7 +52,7 @@ describe('Validation of constraint type specific properties', () => { 'constraints@0/body', ) as PropertyBody; - const props = createJayveeValidationProps(validationAcceptorMock); + const props = createJayveeValidationProps(validationAcceptorMock, services); const wrapper = props.wrapperFactories.TypedObject.wrap( propertyBody.$container.type, @@ -73,7 +75,7 @@ describe('Validation of constraint type specific properties', () => { beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-assignment.ts b/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-assignment.ts index 0cdde161..58ccda73 100644 --- a/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-assignment.ts @@ -3,7 +3,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import { - PrimitiveValuetypes, type PropertyAssignment, type PropertySpecification, evaluatePropertyValue, @@ -54,7 +53,7 @@ function checkNonNegative( property, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.Integer, + props.valueTypeProvider.Primitives.Integer, ); if (value === undefined) { return; diff --git a/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-body.spec.ts b/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-body.spec.ts index 50d75178..8757a251 100644 --- a/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-body.spec.ts +++ b/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-body.spec.ts @@ -9,7 +9,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type PropertyBody, createJayveeServices } from '../../..'; +import { + type JayveeServices, + type PropertyBody, + createJayveeServices, +} from '../../..'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation of constraint type specific property bodies', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -45,7 +50,7 @@ describe('Validation of constraint type specific property bodies', () => { 'constraints@0/body', ) as PropertyBody; - const props = createJayveeValidationProps(validationAcceptorMock); + const props = createJayveeValidationProps(validationAcceptorMock, services); const wrapper = props.wrapperFactories.TypedObject.wrap( propertyBody.$container.type, @@ -57,7 +62,7 @@ describe('Validation of constraint type specific property bodies', () => { beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-body.ts b/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-body.ts index 87ab3979..a51c9eaa 100644 --- a/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-body.ts +++ b/libs/language-server/src/lib/validation/checks/constrainttype-specific/property-body.ts @@ -2,11 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { - PrimitiveValuetypes, - type PropertyBody, - evaluatePropertyValue, -} from '../../../ast'; +import { type PropertyBody, evaluatePropertyValue } from '../../../ast'; import { type JayveeValidationProps } from '../../validation-registry'; export function checkConstraintTypeSpecificPropertyBody( @@ -41,13 +37,13 @@ function checkLengthConstraintPropertyBody( minLengthProperty, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.Integer, + props.valueTypeProvider.Primitives.Integer, ); const maxLength = evaluatePropertyValue( maxLengthProperty, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.Integer, + props.valueTypeProvider.Primitives.Integer, ); if (minLength === undefined || maxLength === undefined) { return; @@ -83,13 +79,13 @@ function checkRangeConstraintPropertyBody( lowerBoundProperty, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.Decimal, + props.valueTypeProvider.Primitives.Decimal, ); const upperBound = evaluatePropertyValue( upperBoundProperty, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.Decimal, + props.valueTypeProvider.Primitives.Decimal, ); if (lowerBound === undefined || upperBound === undefined) { return; @@ -120,7 +116,7 @@ function checkRangeConstraintPropertyBody( lowerBoundInclusiveProperty, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.Boolean, + props.valueTypeProvider.Primitives.Boolean, ); if (expressionValue === undefined) { return; @@ -134,7 +130,7 @@ function checkRangeConstraintPropertyBody( upperBoundInclusiveProperty, props.evaluationContext, props.wrapperFactories, - PrimitiveValuetypes.Boolean, + props.valueTypeProvider.Primitives.Boolean, ); if (expressionValue === undefined) { return; 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 16106969..58209eca 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,6 +11,7 @@ import { NodeFileSystem } from 'langium/node'; import { type ExpressionConstraintDefinition, + type JayveeServices, createJayveeServices, } from '../../../lib'; import { @@ -33,6 +34,7 @@ describe('Validation of ConstraintDefinition (expression syntax)', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -51,13 +53,13 @@ describe('Validation of ConstraintDefinition (expression syntax)', () => { validateExpressionConstraintDefinition( expressionConstraint, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/language-server/src/lib/validation/checks/expression-constraint-definition.ts b/libs/language-server/src/lib/validation/checks/expression-constraint-definition.ts index b120f9b2..6c7082ef 100644 --- a/libs/language-server/src/lib/validation/checks/expression-constraint-definition.ts +++ b/libs/language-server/src/lib/validation/checks/expression-constraint-definition.ts @@ -9,7 +9,6 @@ import { inferExpressionType } from '../../ast/expressions/type-inference'; import { type ExpressionConstraintDefinition } from '../../ast/generated/ast'; -import { PrimitiveValuetypes } from '../../ast/wrappers/value-type/primitive/primitive-value-types'; import { type JayveeValidationProps } from '../validation-registry'; import { checkExpressionSimplification } from '../validation-util'; @@ -25,12 +24,17 @@ function checkConstraintExpression( props: JayveeValidationProps, ): void { const expression = constraint?.expression; - const inferredType = inferExpressionType(expression, props.validationContext); + const inferredType = inferExpressionType( + expression, + props.validationContext, + props.valueTypeProvider, + props.wrapperFactories, + ); if (inferredType === undefined) { return; } - const expectedType = PrimitiveValuetypes.Boolean; + const expectedType = props.valueTypeProvider.Primitives.Boolean; if (!inferredType.isConvertibleTo(expectedType)) { props.validationContext.accept( 'error', 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 689bad5a..06c0f8d7 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 @@ -5,7 +5,11 @@ import { type AstNode, type LangiumDocument } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type JayveeModel, createJayveeServices } from '../../../lib'; +import { + type JayveeModel, + type JayveeServices, + createJayveeServices, +} from '../../../lib'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -23,6 +27,8 @@ describe('Validation of JayveeModel', () => { options?: ParseHelperOptions, ) => Promise>; + let services: JayveeServices; + const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); const readJvTestAsset = readJvTestAssetHelper( @@ -38,13 +44,13 @@ describe('Validation of JayveeModel', () => { validateJayveeModel( jayveeModel, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; // Parse function for Jayvee (without validation) parse = parseHelper(services); }); 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 a144fe31..c6b69a46 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,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type PipeDefinition, createJayveeServices } from '../../../lib'; +import { + type JayveeServices, + type PipeDefinition, + createJayveeServices, +} from '../../../lib'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation of PipeDefinition', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -47,13 +52,13 @@ describe('Validation of PipeDefinition', () => { validatePipeDefinition( pipe, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); 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 1733a5e0..fe430c71 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,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type PipelineDefinition, createJayveeServices } from '../../../lib'; +import { + type JayveeServices, + type PipelineDefinition, + createJayveeServices, +} from '../../../lib'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation of PipelineDefinition', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -47,13 +52,13 @@ describe('Validation of PipelineDefinition', () => { validatePipelineDefinition( pipeline, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); 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 e0f93e62..9568058d 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 @@ -10,6 +10,7 @@ import { import { NodeFileSystem } from 'langium/node'; import { + type JayveeServices, type PropertyAssignment, type PropertyBody, type TypedObjectWrapper, @@ -35,6 +36,7 @@ describe('Validation of PropertyAssignment', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -52,7 +54,7 @@ describe('Validation of PropertyAssignment', () => { const type = propertyBody.$container.type; - const props = createJayveeValidationProps(validationAcceptorMock); + const props = createJayveeValidationProps(validationAcceptorMock, services); const wrapper = props.wrapperFactories.TypedObject.wrap(type); expect(wrapper).toBeDefined(); @@ -70,7 +72,7 @@ describe('Validation of PropertyAssignment', () => { beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); 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 98f9ad8d..e53e1f7a 100644 --- a/libs/language-server/src/lib/validation/checks/property-assignment.ts +++ b/libs/language-server/src/lib/validation/checks/property-assignment.ts @@ -91,6 +91,8 @@ function checkPropertyValueTyping( const inferredType = inferExpressionType( propertyValue, props.validationContext, + props.valueTypeProvider, + props.wrapperFactories, ); if (inferredType === undefined) { return; 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 86fc1014..2297be7b 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 @@ -9,7 +9,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type PropertyBody, createJayveeServices } from '../../../lib'; +import { + type JayveeServices, + type PropertyBody, + createJayveeServices, +} from '../../../lib'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation PropertyBody', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -47,13 +52,13 @@ describe('Validation PropertyBody', () => { validatePropertyBody( propertyBody, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); 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 8d78b241..01701a17 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,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type RangeLiteral, createJayveeServices } from '../../../lib'; +import { + type JayveeServices, + type RangeLiteral, + createJayveeServices, +} from '../../../lib'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation of RangeLiteral', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -47,13 +52,13 @@ describe('Validation of RangeLiteral', () => { validateRangeLiteral( rangeLiteral, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); 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 9bc4da3e..46f98434 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,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type RegexLiteral, createJayveeServices } from '../../../lib'; +import { + type JayveeServices, + type RegexLiteral, + createJayveeServices, +} from '../../../lib'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation of RegexLiteral', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -47,13 +52,13 @@ describe('Validation of RegexLiteral', () => { validateRegexLiteral( regexLiteral, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); 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 66178314..8e3fbfa7 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 @@ -9,7 +9,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type TransformBody, createJayveeServices } from '../../../lib'; +import { + type JayveeServices, + type TransformBody, + createJayveeServices, +} from '../../../lib'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation of TransformBody', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -47,13 +52,13 @@ describe('Validation of TransformBody', () => { validateTransformBody( transformBody, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/language-server/src/lib/validation/checks/transform-output-assigment.ts b/libs/language-server/src/lib/validation/checks/transform-output-assigment.ts index 4300bec9..7e87d402 100644 --- a/libs/language-server/src/lib/validation/checks/transform-output-assigment.ts +++ b/libs/language-server/src/lib/validation/checks/transform-output-assigment.ts @@ -21,7 +21,6 @@ import { isTransformPortDefinition, isUnaryExpression, } from '../../ast/generated/ast'; -import { createValueType } from '../../ast/wrappers/value-type/value-type-util'; import { type JayveeValidationProps } from '../validation-registry'; import { checkExpressionSimplification } from '../validation-util'; @@ -50,12 +49,14 @@ function checkOutputValueTyping( const inferredType = inferExpressionType( assignmentExpression, props.validationContext, + props.valueTypeProvider, + props.wrapperFactories, ); if (inferredType === undefined) { return; } - const expectedType = createValueType(outputType); + const expectedType = props.wrapperFactories.ValueType.wrap(outputType); if (expectedType === undefined) { return; } 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 5116d4c0..6e1cbaa3 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 @@ -10,6 +10,7 @@ import { import { NodeFileSystem } from 'langium/node'; import { + type JayveeServices, type TransformOutputAssignment, createJayveeServices, } from '../../../lib'; @@ -33,6 +34,7 @@ describe('Validation of TransformOutputAssignment', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -51,13 +53,13 @@ describe('Validation of TransformOutputAssignment', () => { validateTransformOutputAssignment( transformOutputAssignment, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); 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 9ed0f840..4bc409b9 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 @@ -10,6 +10,7 @@ import { import { NodeFileSystem } from 'langium/node'; import { + type JayveeServices, type TypedConstraintDefinition, createJayveeServices, initializeWorkspace, @@ -34,6 +35,7 @@ describe('Validation of ConstraintDefinition (typed syntax)', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -51,13 +53,13 @@ describe('Validation of ConstraintDefinition (typed syntax)', () => { validateTypedConstraintDefinition( typedConstraint, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(async () => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; await initializeWorkspace(services); locator = services.workspace.AstNodeLocator; diff --git a/libs/language-server/src/lib/validation/checks/value-type-definition.spec.ts b/libs/language-server/src/lib/validation/checks/value-type-definition.spec.ts index 99ff4725..e25199e5 100644 --- a/libs/language-server/src/lib/validation/checks/value-type-definition.spec.ts +++ b/libs/language-server/src/lib/validation/checks/value-type-definition.spec.ts @@ -9,7 +9,11 @@ import { } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { type ValuetypeDefinition, createJayveeServices } from '../../../lib'; +import { + type JayveeServices, + type ValuetypeDefinition, + createJayveeServices, +} from '../../../lib'; import { type ParseHelperOptions, createJayveeValidationProps, @@ -30,6 +34,7 @@ describe('Validation of ValuetypeDefinition', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -47,13 +52,13 @@ describe('Validation of ValuetypeDefinition', () => { validateValueTypeDefinition( valueTypeDefinition, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); } beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); diff --git a/libs/language-server/src/lib/validation/checks/value-type-definition.ts b/libs/language-server/src/lib/validation/checks/value-type-definition.ts index 20e6dc99..d46fcd53 100644 --- a/libs/language-server/src/lib/validation/checks/value-type-definition.ts +++ b/libs/language-server/src/lib/validation/checks/value-type-definition.ts @@ -13,11 +13,8 @@ import { assertUnreachable } from 'langium'; import { type CollectionLiteral, - CollectionValuetype, type ConstraintDefinition, - PrimitiveValuetypes, type ValueType, - createValueType, evaluateExpression, inferExpressionType, isExpressionConstraintDefinition, @@ -43,7 +40,9 @@ function checkSupertypeCycle( props: JayveeValidationProps, ): void { const hasCycle = - createValueType(valueTypeDefinition)?.hasSupertypeCycle() ?? false; + props.wrapperFactories.ValueType.wrap( + valueTypeDefinition, + )?.hasSupertypeCycle() ?? false; if (hasCycle) { assert(!valueTypeDefinition.isBuiltin); props.validationContext.accept( @@ -69,8 +68,12 @@ function checkConstraintsCollectionValues( const inferredCollectionType = inferExpressionType( constraintCollection, props.validationContext, + props.valueTypeProvider, + props.wrapperFactories, + ); + const expectedType = props.valueTypeProvider.createCollectionValueTypeOf( + props.valueTypeProvider.Primitives.Constraint, ); - const expectedType = new CollectionValuetype(PrimitiveValuetypes.Constraint); if (inferredCollectionType === undefined) { return; } @@ -111,7 +114,8 @@ function checkConstraintMatchesValuetype( diagnosticIndex: number, props: JayveeValidationProps, ): void { - const actualValuetype = createValueType(valueTypeDefinition); + const actualValuetype = + props.wrapperFactories.ValueType.wrap(valueTypeDefinition); const compatibleValuetype = getCompatibleValuetype(constraint, props); if (actualValuetype === undefined || compatibleValuetype === undefined) { @@ -143,7 +147,7 @@ function getCompatibleValuetype( } return props.wrapperFactories.ConstraintType.wrap(constraint.type).on; } else if (isExpressionConstraintDefinition(constraint)) { - return createValueType(constraint?.valueType); + return props.wrapperFactories.ValueType.wrap(constraint?.valueType); } assertUnreachable(constraint); } diff --git a/libs/language-server/src/lib/validation/checks/value-type-reference.spec.ts b/libs/language-server/src/lib/validation/checks/value-type-reference.spec.ts index f43283a9..1e153198 100644 --- a/libs/language-server/src/lib/validation/checks/value-type-reference.spec.ts +++ b/libs/language-server/src/lib/validation/checks/value-type-reference.spec.ts @@ -12,6 +12,7 @@ import { import { NodeFileSystem } from 'langium/node'; import { + type JayveeServices, type ValueTypeReference, type ValuetypeDefinition, createJayveeServices, @@ -36,6 +37,7 @@ describe('Validation of ValueTypeReference', () => { const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -68,7 +70,7 @@ describe('Validation of ValueTypeReference', () => { beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); @@ -88,7 +90,7 @@ describe('Validation of ValueTypeReference', () => { (valueTypeRef) => { validateValueTypeReference( valueTypeRef, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); }, ); @@ -105,7 +107,7 @@ describe('Validation of ValueTypeReference', () => { (valueTypeRef) => { validateValueTypeReference( valueTypeRef, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); }, ); @@ -122,7 +124,7 @@ describe('Validation of ValueTypeReference', () => { (valueTypeRef) => { validateValueTypeReference( valueTypeRef, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); }, ); @@ -139,7 +141,7 @@ describe('Validation of ValueTypeReference', () => { (valueTypeRef) => { validateValueTypeReference( valueTypeRef, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); }, ); @@ -161,7 +163,7 @@ describe('Validation of ValueTypeReference', () => { (valueTypeRef) => { validateValueTypeReference( valueTypeRef, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); }, ); @@ -183,7 +185,7 @@ describe('Validation of ValueTypeReference', () => { (valueTypeRef) => { validateValueTypeReference( valueTypeRef, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); }, ); @@ -205,7 +207,7 @@ describe('Validation of ValueTypeReference', () => { (valueTypeRef) => { validateValueTypeReference( valueTypeRef, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); }, ); @@ -227,7 +229,7 @@ describe('Validation of ValueTypeReference', () => { (valueTypeRef) => { validateValueTypeReference( valueTypeRef, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); }, ); @@ -262,7 +264,7 @@ describe('Validation of ValueTypeReference', () => { validateValueTypeReference( valueTypeRef, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); expect(validationAcceptorMock).toHaveBeenCalledTimes(1); @@ -288,7 +290,7 @@ describe('Validation of ValueTypeReference', () => { validateValueTypeReference( valueTypeRef, - createJayveeValidationProps(validationAcceptorMock), + createJayveeValidationProps(validationAcceptorMock, services), ); expect(validationAcceptorMock).toHaveBeenCalledTimes(0); diff --git a/libs/language-server/src/lib/validation/checks/value-type-reference.ts b/libs/language-server/src/lib/validation/checks/value-type-reference.ts index 044cff4f..35a16fb8 100644 --- a/libs/language-server/src/lib/validation/checks/value-type-reference.ts +++ b/libs/language-server/src/lib/validation/checks/value-type-reference.ts @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import { createValueType } from '../../ast'; import { type ValueTypeReference, isBuiltinBlockTypeDefinition, @@ -49,7 +48,7 @@ function checkIsValueTypeReferenceable( valueTypeRef: ValueTypeReference, props: JayveeValidationProps, ): void { - const valueType = createValueType(valueTypeRef); + const valueType = props.wrapperFactories.ValueType.wrap(valueTypeRef); if (valueType === undefined) { return; } diff --git a/libs/language-server/src/lib/validation/validation-registry.ts b/libs/language-server/src/lib/validation/validation-registry.ts index bee16675..71dfd37c 100644 --- a/libs/language-server/src/lib/validation/validation-registry.ts +++ b/libs/language-server/src/lib/validation/validation-registry.ts @@ -14,6 +14,7 @@ import { EvaluationContext, type OperatorEvaluatorRegistry, type OperatorTypeComputerRegistry, + type ValueTypeProvider, type WrapperFactoryProvider, } from '../ast'; import { type JayveeAstType } from '../ast/generated/ast'; @@ -45,6 +46,7 @@ export class JayveeValidationRegistry extends ValidationRegistry { private readonly typeComputerRegistry: OperatorTypeComputerRegistry; private readonly operatorEvaluatorRegistry: OperatorEvaluatorRegistry; private readonly wrapperFactories: WrapperFactoryProvider; + private readonly valueTypeProvider: ValueTypeProvider; constructor(services: JayveeServices) { super(services); @@ -53,6 +55,7 @@ export class JayveeValidationRegistry extends ValidationRegistry { this.typeComputerRegistry = services.operators.TypeComputerRegistry; this.operatorEvaluatorRegistry = services.operators.EvaluatorRegistry; this.wrapperFactories = services.WrapperFactories; + this.valueTypeProvider = services.ValueTypeProvider; this.registerJayveeValidationChecks({ BuiltinBlockTypeDefinition: validateBlockTypeDefinition, @@ -81,6 +84,7 @@ export class JayveeValidationRegistry extends ValidationRegistry { this.typeComputerRegistry, this.operatorEvaluatorRegistry, this.wrapperFactories, + this.valueTypeProvider, ); this.doRegister(type, this.wrapValidationException(wrappedCheck, this)); @@ -93,6 +97,7 @@ export class JayveeValidationRegistry extends ValidationRegistry { typeComputerRegistry: OperatorTypeComputerRegistry, operatorEvaluatorRegistry: OperatorEvaluatorRegistry, wrapperFactories: WrapperFactoryProvider, + valueTypeProvider: ValueTypeProvider, ): ValidationCheck { return (node: T, accept: ValidationAcceptor): MaybePromise => { const validationContext = new ValidationContext( @@ -102,11 +107,13 @@ export class JayveeValidationRegistry extends ValidationRegistry { const evaluationContext = new EvaluationContext( runtimeParameterProvider, operatorEvaluatorRegistry, + valueTypeProvider, ); return check(node, { validationContext: validationContext, evaluationContext: evaluationContext, wrapperFactories: wrapperFactories, + valueTypeProvider: valueTypeProvider, }); }; } @@ -122,6 +129,7 @@ export interface JayveeValidationProps { validationContext: ValidationContext; evaluationContext: EvaluationContext; wrapperFactories: WrapperFactoryProvider; + valueTypeProvider: ValueTypeProvider; } export type JayveeValidationCheck = ( node: T, 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 b7bf7d97..ae68f18f 100644 --- a/libs/language-server/src/lib/validation/validation-utils.spec.ts +++ b/libs/language-server/src/lib/validation/validation-utils.spec.ts @@ -10,9 +10,13 @@ import { import { NodeFileSystem } from 'langium/node'; import { + DefaultOperatorEvaluatorRegistry, DefaultOperatorTypeComputerRegistry, + type JayveeServices, type PropertyBody, ValidationContext, + ValueTypeProvider, + WrapperFactoryProvider, checkUniqueNames, createJayveeServices, } from '..'; @@ -31,6 +35,7 @@ describe('Validation of validation-utils', () => { ) => Promise>; let locator: AstNodeLocator; + let services: JayveeServices; const readJvTestAsset = readJvTestAssetHelper( __dirname, @@ -51,7 +56,7 @@ describe('Validation of validation-utils', () => { beforeAll(() => { // Create language services - const services = createJayveeServices(NodeFileSystem).Jayvee; + services = createJayveeServices(NodeFileSystem).Jayvee; locator = services.workspace.AstNodeLocator; // Parse function for Jayvee (without validation) parse = parseHelper(services); @@ -69,6 +74,7 @@ describe('Validation of validation-utils', () => { const text = readJvTestAsset( 'validation-utils/valid-distinct-property-names.jv', ); + const valueTypeProvider = new ValueTypeProvider(); const propertyBody: PropertyBody = await parseAndExtractPropertyBody( text, @@ -77,7 +83,13 @@ describe('Validation of validation-utils', () => { propertyBody.properties, new ValidationContext( validationAcceptorMock, - new DefaultOperatorTypeComputerRegistry(), + new DefaultOperatorTypeComputerRegistry( + valueTypeProvider, + new WrapperFactoryProvider( + new DefaultOperatorEvaluatorRegistry(), + valueTypeProvider, + ), + ), ), ); @@ -88,6 +100,7 @@ describe('Validation of validation-utils', () => { const text = readJvTestAsset( 'validation-utils/invalid-duplicate-property-names.jv', ); + const valueTypeProvider = new ValueTypeProvider(); const propertyBody: PropertyBody = await parseAndExtractPropertyBody( text, @@ -96,7 +109,13 @@ describe('Validation of validation-utils', () => { propertyBody.properties, new ValidationContext( validationAcceptorMock, - new DefaultOperatorTypeComputerRegistry(), + new DefaultOperatorTypeComputerRegistry( + valueTypeProvider, + new WrapperFactoryProvider( + new DefaultOperatorEvaluatorRegistry(), + valueTypeProvider, + ), + ), ), ); diff --git a/libs/language-server/src/test/utils.ts b/libs/language-server/src/test/utils.ts index e11ca33d..cf2d7405 100644 --- a/libs/language-server/src/test/utils.ts +++ b/libs/language-server/src/test/utils.ts @@ -14,14 +14,10 @@ import { import { type WorkspaceFolder } from 'vscode-languageserver-protocol'; import { - DefaultOperatorEvaluatorRegistry, - DefaultOperatorTypeComputerRegistry, EvaluationContext, type JayveeServices, type JayveeValidationProps, - RuntimeParameterProvider, ValidationContext, - WrapperFactoryProvider, } from '../lib'; import { initializeWorkspace } from '../lib/builtin-library/jayvee-workspace-manager'; @@ -73,13 +69,13 @@ export async function loadTestExtensions( export function createJayveeValidationProps( validationAcceptor: ValidationAcceptor, + services: JayveeServices, ): JayveeValidationProps { - const operatorTypeComputerRegistry = - new DefaultOperatorTypeComputerRegistry(); - const operatorEvaluatorRegistry = new DefaultOperatorEvaluatorRegistry(); - const wrapperFactories = new WrapperFactoryProvider( - operatorEvaluatorRegistry, - ); + const valueTypeProvider = services.ValueTypeProvider; + const operatorEvaluatorRegistry = services.operators.EvaluatorRegistry; + const wrapperFactories = services.WrapperFactories; + const operatorTypeComputerRegistry = services.operators.TypeComputerRegistry; + const runtimeParameterProvider = services.RuntimeParameterProvider; return { validationContext: new ValidationContext( @@ -87,9 +83,11 @@ export function createJayveeValidationProps( operatorTypeComputerRegistry, ), evaluationContext: new EvaluationContext( - new RuntimeParameterProvider(), + runtimeParameterProvider, operatorEvaluatorRegistry, + valueTypeProvider, ), + valueTypeProvider: valueTypeProvider, wrapperFactories: wrapperFactories, }; }