UNPKG

@finos/legend-extension-dsl-data-space

Version:
442 lines 26.9 kB
/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import packageJson from '../../../../package.json' with { type: 'json' }; import V1_SYSTEM_MODELS from './v1/V1_DSL_DataSpace_SystemModels.json' with { type: 'json' }; import { V1_DataSpace, V1_DataSpaceDiagram, V1_DataSpaceElementPointer, V1_DataSpaceExecutionContext, V1_DataSpacePackageableElementExecutable, V1_DataSpaceSupportCombinedInfo, V1_DataSpaceSupportEmail, V1_DataSpaceTemplateExecutable, } from './v1/model/packageableElements/dataSpace/V1_DSL_DataSpace_DataSpace.js'; import { guaranteeNonEmptyString, guaranteeNonNullable, UnsupportedOperationError, isNonNullable, assertType, guaranteeType, returnUndefOnError, } from '@finos/legend-shared'; import { deserialize } from 'serializr'; import { V1_DATA_SPACE_ELEMENT_PROTOCOL_TYPE, V1_deserializeDataSpace, V1_MAPPING_INCLUDE_DATASPACE_TYPE, V1_serializeDataSpace, V1_serializeMappingInclude, V1_deserializeMappingInclude, } from './v1/transformation/pureProtocol/V1_DSL_DataSpace_ProtocolHelper.js'; import { V1_resolveDataSpace } from './v1/transformation/pureGraph/V1_DSL_DataSpace_GraphBuilderHelper.js'; import { getOwnDataSpace } from '../../DSL_DataSpace_GraphManagerHelper.js'; import { DataSpace, DataSpaceExecutionContext, DataSpaceSupportCombinedInfo, DataSpaceSupportEmail, DataSpaceDiagram, DataSpaceElementPointer, DataSpaceExecutableTemplate, DataSpacePackageableElementExecutable, } from '../../../graph/metamodel/pure/model/packageableElements/dataSpace/DSL_DataSpace_DataSpace.js'; import { V1_taggedValueModelSchema, PackageableElementExplicitReference, V1_PackageableElementPointer, PackageableElementPointerType, V1_buildTaggedValue, V1_transformStereotype, V1_transformTaggedValue, PureProtocolProcessorPlugin, V1_ElementBuilder, V1_initPackageableElement, V1_buildFullPath, Class, Enumeration, Association, Package, V1_RawValueSpecificationTransformer, V1_buildRawLambdaWithResolvedPaths, V1_buildEmbeddedData, V1_transformEmbeddedData, DataElementReference, V1_DataElementReference, QueryDataSpaceExecutionContextInfo, generateFunctionPrettyName, ConcreteFunctionDefinition, } from '@finos/legend-graph'; import { V1_resolveDiagram } from '@finos/legend-extension-dsl-diagram/graph'; import { V1_MappingIncludeDataSpace } from './v1/model/packageableElements/mapping/V1_DSL_DataSpace_MappingIncludeDataSpace.js'; import { MappingIncludeDataSpace } from '../../../graph/metamodel/pure/model/packageableElements/mapping/DSL_DataSpace_MappingIncludeDataSpace.js'; export const DATA_SPACE_ELEMENT_CLASSIFIER_PATH = 'meta::pure::metamodel::dataSpace::DataSpace'; export const DATA_SPACE_ELEMENT_POINTER = 'DATASPACE'; export class DSL_DataSpace_PureProtocolProcessorPlugin extends PureProtocolProcessorPlugin { constructor() { super(packageJson.extensions.pureProtocolProcessorPlugin, packageJson.version); } V1_getExtraElementBuilders() { return [ new V1_ElementBuilder({ elementClassName: 'DataSpace', _class: V1_DataSpace, firstPass: (elementProtocol, context) => { assertType(elementProtocol, V1_DataSpace); const element = new DataSpace(elementProtocol.name); const path = V1_buildFullPath(elementProtocol.package, elementProtocol.name); element.executionContexts = guaranteeNonNullable(elementProtocol.executionContexts, `Data product 'executionContexts' field is missing`).map((contextProtocol) => { const execContext = new DataSpaceExecutionContext(); execContext.name = guaranteeNonEmptyString(contextProtocol.name, `Data product execution context 'name' field is missing or empty`); execContext.title = contextProtocol.title; execContext.description = contextProtocol.description; execContext.mapping = PackageableElementExplicitReference.create(context.graph.getMapping(contextProtocol.mapping.path)); execContext.defaultRuntime = PackageableElementExplicitReference.create(context.graph.getRuntime(contextProtocol.defaultRuntime.path)); execContext.testData = contextProtocol.testData ? guaranteeType(V1_buildEmbeddedData(contextProtocol.testData, context), DataElementReference) : undefined; return execContext; }); element.defaultExecutionContext = guaranteeNonNullable(element.executionContexts.find((execContext) => execContext.name === guaranteeNonEmptyString(elementProtocol.defaultExecutionContext, `Data product 'defaultExecutionContext' field is missing or empty`)), `Can't find default execution context '${elementProtocol.defaultExecutionContext}'`); context.currentSubGraph.setOwnElementInExtension(path, element, DataSpace); return element; }, secondPass: (elementProtocol, context) => { assertType(elementProtocol, V1_DataSpace); const path = V1_buildFullPath(elementProtocol.package, elementProtocol.name); const element = getOwnDataSpace(path, context.currentSubGraph); element.stereotypes = elementProtocol.stereotypes .map((stereotype) => context.resolveStereotype(stereotype)) .filter(isNonNullable); element.taggedValues = elementProtocol.taggedValues .map((taggedValue) => V1_buildTaggedValue(taggedValue, context)) .filter(isNonNullable); element.title = elementProtocol.title; element.description = elementProtocol.description; if (elementProtocol.elements) { element.elements = elementProtocol.elements.map((pointer) => { const elementReference = context.resolveElement(pointer.path, true); if (elementReference.value instanceof Package || elementReference.value instanceof Class || elementReference.value instanceof Enumeration || elementReference.value instanceof Association) { const elementPointer = new DataSpaceElementPointer(); elementPointer.element = elementReference; elementPointer.exclude = pointer.exclude; return elementPointer; } throw new UnsupportedOperationError(`Can't find data product element (only allow packages, classes, enumerations, and associations) '${pointer.path}'`); }); } if (elementProtocol.executables) { element.executables = elementProtocol.executables.map((executableProtocol) => { if (executableProtocol instanceof V1_DataSpaceTemplateExecutable) { const executable = new DataSpaceExecutableTemplate(); if (executableProtocol.id) { executable.id = executableProtocol.id; } executable.title = executableProtocol.title; executable.description = executableProtocol.description; executable.query = V1_buildRawLambdaWithResolvedPaths(executableProtocol.query.parameters, executableProtocol.query.body, context); if (executableProtocol.executionContextKey) { executable.executionContextKey = executableProtocol.executionContextKey; } return executable; } else if (executableProtocol instanceof V1_DataSpacePackageableElementExecutable) { const executable = new DataSpacePackageableElementExecutable(); if (executableProtocol.id) { executable.id = executableProtocol.id; } executable.title = executableProtocol.title; executable.description = executableProtocol.description; if (executableProtocol.executionContextKey) { executable.executionContextKey = executableProtocol.executionContextKey; } try { executable.executable = context.resolveElement(executableProtocol.executable.path, false); } catch { try { executable.executable = PackageableElementExplicitReference.create(guaranteeNonNullable(context.graph.functions.find((fn) => generateFunctionPrettyName(fn, { fullPath: true, spacing: false, notIncludeParamName: true, }) === executableProtocol.executable.path.replaceAll(/\s*/gu, '')))); } catch { throw new UnsupportedOperationError(`Can't analyze data product executable with element in path: ${executableProtocol.executable.path}`, executableProtocol); } } return executable; } else { throw new UnsupportedOperationError(`Can't build data product executable`, executableProtocol); } }); } if (elementProtocol.diagrams) { element.diagrams = elementProtocol.diagrams.map((diagramProtocol) => { const diagram = new DataSpaceDiagram(); diagram.title = diagramProtocol.title; diagram.description = diagramProtocol.description; diagram.diagram = V1_resolveDiagram(diagramProtocol.diagram.path, context); return diagram; }); } if (elementProtocol.supportInfo) { if (elementProtocol.supportInfo instanceof V1_DataSpaceSupportEmail) { const supportEmail = new DataSpaceSupportEmail(); supportEmail.documentationUrl = elementProtocol.supportInfo.documentationUrl; supportEmail.address = guaranteeNonEmptyString(elementProtocol.supportInfo.address, `Data product support email 'address' field is missing or empty`); element.supportInfo = supportEmail; } else if (elementProtocol.supportInfo instanceof V1_DataSpaceSupportCombinedInfo) { const combinedInfo = new DataSpaceSupportCombinedInfo(); combinedInfo.documentationUrl = elementProtocol.supportInfo.documentationUrl; combinedInfo.emails = elementProtocol.supportInfo.emails; combinedInfo.website = elementProtocol.supportInfo.website; combinedInfo.faqUrl = elementProtocol.supportInfo.faqUrl; combinedInfo.supportUrl = elementProtocol.supportInfo.supportUrl; element.supportInfo = combinedInfo; } else { throw new UnsupportedOperationError(`Can't build data product support info`, elementProtocol.supportInfo); } } }, }), ]; } V1_getExtraSystemModels() { return [V1_SYSTEM_MODELS]; } V1_getExtraElementClassifierPathGetters() { return [ (elementProtocol) => { if (elementProtocol instanceof V1_DataSpace) { return DATA_SPACE_ELEMENT_CLASSIFIER_PATH; } return undefined; }, ]; } V1_getExtraElementPointerTypes() { return [ (elementProtocol) => { if (elementProtocol instanceof DataSpace) { return DATA_SPACE_ELEMENT_POINTER; } return undefined; }, ]; } V1_getExtraElementProtocolSerializers() { return [ (elementProtocol, plugins) => { if (elementProtocol instanceof V1_DataSpace) { return V1_serializeDataSpace(elementProtocol); } return undefined; }, ]; } V1_getExtraElementProtocolDeserializers() { return [ (json, plugins) => { if (json._type === V1_DATA_SPACE_ELEMENT_PROTOCOL_TYPE) { return V1_deserializeDataSpace(json); } return undefined; }, ]; } V1_getExtraElementTransformers() { return [ (metamodel, context) => { if (metamodel instanceof DataSpace) { const protocol = new V1_DataSpace(); V1_initPackageableElement(protocol, metamodel); protocol.stereotypes = metamodel.stereotypes.map(V1_transformStereotype); protocol.taggedValues = metamodel.taggedValues.map(V1_transformTaggedValue); protocol.executionContexts = metamodel.executionContexts.map((execContext) => { const contextProtocol = new V1_DataSpaceExecutionContext(); contextProtocol.name = execContext.name; contextProtocol.title = execContext.title; contextProtocol.description = execContext.description; contextProtocol.mapping = new V1_PackageableElementPointer(PackageableElementPointerType.MAPPING, execContext.mapping.valueForSerialization ?? ''); contextProtocol.defaultRuntime = new V1_PackageableElementPointer(PackageableElementPointerType.RUNTIME, execContext.defaultRuntime.valueForSerialization ?? ''); contextProtocol.testData = execContext.testData ? guaranteeType(V1_transformEmbeddedData(execContext.testData, context), V1_DataElementReference) : undefined; return contextProtocol; }); protocol.defaultExecutionContext = metamodel.defaultExecutionContext.name; protocol.title = metamodel.title; protocol.description = metamodel.description; protocol.elements = metamodel.elements?.map((pointer) => { const elementPointer = new V1_DataSpaceElementPointer(); elementPointer.exclude = pointer.exclude; elementPointer.path = pointer.element.valueForSerialization ?? ''; return elementPointer; }); protocol.executables = metamodel.executables?.map((executable) => { if (executable instanceof DataSpaceExecutableTemplate) { const executableProtocol = new V1_DataSpaceTemplateExecutable(); if (executable.id) { executableProtocol.id = executable.id; } executableProtocol.title = executable.title; executableProtocol.description = executable.description; if (executable.executionContextKey) { executableProtocol.executionContextKey = executable.executionContextKey; } executableProtocol.query = executable.query.accept_RawValueSpecificationVisitor(new V1_RawValueSpecificationTransformer(context)); return executableProtocol; } else if (executable instanceof DataSpacePackageableElementExecutable) { const executableProtocol = new V1_DataSpacePackageableElementExecutable(); if (executable.id) { executableProtocol.id = executable.id; } executableProtocol.title = executable.title; executableProtocol.description = executable.description; if (executable.executionContextKey) { executableProtocol.executionContextKey = executable.executionContextKey; } if (executable.executable.value instanceof ConcreteFunctionDefinition) { executableProtocol.executable = new V1_PackageableElementPointer(PackageableElementPointerType.FUNCTION, generateFunctionPrettyName(executable.executable.value, { fullPath: true, spacing: false, notIncludeParamName: true, })); } else { executableProtocol.executable = new V1_PackageableElementPointer(undefined, executable.executable.valueForSerialization ?? ''); } return executableProtocol; } else { throw new UnsupportedOperationError(`Can't transform data product executable`, executable); } }); protocol.diagrams = metamodel.diagrams?.map((diagram) => { const diagramProtocol = new V1_DataSpaceDiagram(); diagramProtocol.title = diagram.title; diagramProtocol.description = diagram.description; diagramProtocol.diagram = new V1_PackageableElementPointer(undefined, diagram.diagram.valueForSerialization ?? ''); return diagramProtocol; }); if (metamodel.supportInfo) { if (metamodel.supportInfo instanceof DataSpaceSupportEmail) { const supportEmail = new V1_DataSpaceSupportEmail(); supportEmail.documentationUrl = metamodel.supportInfo.documentationUrl; supportEmail.address = metamodel.supportInfo.address; protocol.supportInfo = supportEmail; } else if (metamodel.supportInfo instanceof DataSpaceSupportCombinedInfo) { const combinedInfo = new V1_DataSpaceSupportCombinedInfo(); combinedInfo.documentationUrl = metamodel.supportInfo.documentationUrl; combinedInfo.emails = metamodel.supportInfo.emails; combinedInfo.website = metamodel.supportInfo.website; combinedInfo.faqUrl = metamodel.supportInfo.faqUrl; combinedInfo.supportUrl = metamodel.supportInfo.supportUrl; protocol.supportInfo = combinedInfo; } else { throw new UnsupportedOperationError(`Can't transform data product support info`, metamodel.supportInfo); } } return protocol; } return undefined; }, ]; } V1_getExtraMappingIncludeBuilders() { return [ (protocol, parentMapping, context) => { if (protocol instanceof V1_MappingIncludeDataSpace) { const dataSpace = V1_resolveDataSpace(protocol.includedDataSpace, context); const includedMapping = new MappingIncludeDataSpace(parentMapping, dataSpace.value.defaultExecutionContext.mapping, dataSpace); return includedMapping; } return undefined; }, ]; } V1_getExtraMappingIncludeTransformers() { return [ (metamodel, context) => { if (metamodel instanceof MappingIncludeDataSpace) { const mappingInclude = new V1_MappingIncludeDataSpace(); mappingInclude.includedDataSpace = metamodel.includedDataSpace.valueForSerialization ?? ''; return mappingInclude; } return undefined; }, ]; } V1_getExtraMappingIncludeProtocolSerializers() { return [ (protocol) => { if (protocol instanceof V1_MappingIncludeDataSpace) { return V1_serializeMappingInclude(protocol); } return undefined; }, ]; } V1_getExtraMappingIncludeProtocolDeserializers() { return [ (json) => { if (json._type === V1_MAPPING_INCLUDE_DATASPACE_TYPE) { return V1_deserializeMappingInclude(json); } return undefined; }, ]; } V1_getExtraMappingIncludeIdentifierBuilders() { return [ (protocol) => { if (protocol instanceof V1_MappingIncludeDataSpace) { return protocol.includedDataSpace; } return undefined; }, ]; } V1_getExtraSavedQueryExecutionBuilder() { return [ (queryExec, entites) => { if (queryExec instanceof QueryDataSpaceExecutionContextInfo) { const dataSpace = queryExec.dataSpacePath; const dataSpaceEntity = entites.find((e) => e.path === dataSpace); if (dataSpaceEntity) { const content = dataSpaceEntity.content; if (content._type === V1_DATA_SPACE_ELEMENT_PROTOCOL_TYPE) { const v1DataSpace = returnUndefOnError(() => V1_deserializeDataSpace(content)); if (v1DataSpace) { if (v1DataSpace.executionContexts.length === 1) { const exec = guaranteeNonNullable(v1DataSpace.executionContexts[0]); return { mapping: exec.mapping.path, runtime: exec.defaultRuntime.path, }; } const resvoled = queryExec.executionKey ?? v1DataSpace.defaultExecutionContext; const resolvedExec = guaranteeNonNullable(v1DataSpace.executionContexts.find((e) => e.name === resvoled)); return { mapping: resolvedExec.mapping.path, runtime: resolvedExec.defaultRuntime.path, }; } } } } return undefined; }, ]; } } export const extractDataSpaceTaxonomyNodes = (json) => { const ENTERPRISE_PROFILE_PATH = `meta::pure::profiles::enterprise`; const TAXONOMY_NODES_TAG = `taxonomyNodes`; const TAXONOMY_NODES_TAG_VALUE_DELIMITER = `,`; const taxonomyNodes = new Set(); if (json._type === V1_DATA_SPACE_ELEMENT_PROTOCOL_TYPE) { if (Array.isArray(json.taggedValues)) { const taggedValues = json.taggedValues.map((taggedValueJson) => deserialize(V1_taggedValueModelSchema, taggedValueJson)); taggedValues .filter((taggedValue) => taggedValue.tag.profile === ENTERPRISE_PROFILE_PATH && taggedValue.tag.value === TAXONOMY_NODES_TAG) .forEach((taggedValue) => { taggedValue.value .split(TAXONOMY_NODES_TAG_VALUE_DELIMITER) .map((value) => value.trim()) .filter((value) => Boolean(value)) .forEach((value) => taxonomyNodes.add(value)); }); } } return Array.from(taxonomyNodes.values()); }; //# sourceMappingURL=DSL_DataSpace_PureProtocolProcessorPlugin.js.map