UNPKG

@accordproject/concerto-cto

Version:
435 lines 17 kB
"use strict"; /* * 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. */ const concerto_metamodel_1 = require("@accordproject/concerto-metamodel"); /** * Returns true if the metamodel is a MapDeclaration * @param {object} mm - the metamodel * @return {boolean} the string for that model */ function isMap(mm) { return mm.$class === `${concerto_metamodel_1.MetaModelNamespace}.MapDeclaration`; } /** * Returns true if the metamodel is a ScalarDeclaration * @param {object} mm - the metamodel * @return {boolean} the string for that model */ function isScalar(mm) { return [ `${concerto_metamodel_1.MetaModelNamespace}.BooleanScalar`, `${concerto_metamodel_1.MetaModelNamespace}.IntegerScalar`, `${concerto_metamodel_1.MetaModelNamespace}.LongScalar`, `${concerto_metamodel_1.MetaModelNamespace}.DoubleScalar`, `${concerto_metamodel_1.MetaModelNamespace}.StringScalar`, `${concerto_metamodel_1.MetaModelNamespace}.DateTimeScalar`, ].includes(mm.$class); } /** * Create decorator argument string from a metamodel * @param {object} mm - the metamodel * @return {string} the string for the decorator argument */ function decoratorArgFromMetaModel(mm) { let result = ''; switch (mm.$class) { case `${concerto_metamodel_1.MetaModelNamespace}.DecoratorTypeReference`: const typeRef = mm; result += `${typeRef.type.name}${!!typeRef.isArray ? '[]' : ''}`; break; case `${concerto_metamodel_1.MetaModelNamespace}.DecoratorString`: const strRef = mm; result += `"${strRef.value}"`; break; default: result += `${mm.value}`; break; } return result; } /** * Create decorator string from a metamodel * @param {object} mm - the metamodel * @return {string} the string for the decorator */ function decoratorFromMetaModel(mm) { let result = ''; result += `@${mm.name}`; if (mm.arguments) { result += '('; result += mm.arguments.map(decoratorArgFromMetaModel).join(','); result += ')'; } return result; } /** * Create decorators string from a metamodel * @param {object} mm - the metamodel * @param {string} prefix - indentation * @return {string} the string for the decorators */ function decoratorsFromMetaModel(mm, prefix) { let result = ''; result += mm.map(decoratorFromMetaModel).join(`\n${prefix}`); result += `\n${prefix}`; return result; } /** * Create type string from a metamodel * * @param {object} mm - the metamodel * @return {string} the string for the type */ function typeFromMetaModel(mm) { let result = ''; switch (mm.$class) { case `${concerto_metamodel_1.MetaModelNamespace}.EnumProperty`: break; case `${concerto_metamodel_1.MetaModelNamespace}.BooleanScalar`: case `${concerto_metamodel_1.MetaModelNamespace}.BooleanProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.BooleanMapValueType`: result += ' Boolean'; break; case `${concerto_metamodel_1.MetaModelNamespace}.DateTimeProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.DateTimeScalar`: case `${concerto_metamodel_1.MetaModelNamespace}.DateTimeMapKeyType`: case `${concerto_metamodel_1.MetaModelNamespace}.DateTimeMapValueType`: result += ' DateTime'; break; case `${concerto_metamodel_1.MetaModelNamespace}.DoubleProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.DoubleScalar`: case `${concerto_metamodel_1.MetaModelNamespace}.DoubleMapValueType`: result += ' Double'; break; case `${concerto_metamodel_1.MetaModelNamespace}.IntegerProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.IntegerScalar`: case `${concerto_metamodel_1.MetaModelNamespace}.IntegerMapValueType`: result += ' Integer'; break; case `${concerto_metamodel_1.MetaModelNamespace}.LongProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.LongScalar`: case `${concerto_metamodel_1.MetaModelNamespace}.LongMapValueType`: result += ' Long'; break; case `${concerto_metamodel_1.MetaModelNamespace}.StringProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.StringScalar`: case `${concerto_metamodel_1.MetaModelNamespace}.StringMapKeyType`: case `${concerto_metamodel_1.MetaModelNamespace}.StringMapValueType`: result += ' String'; break; case `${concerto_metamodel_1.MetaModelNamespace}.ObjectProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.ObjectMapKeyType`: case `${concerto_metamodel_1.MetaModelNamespace}.ObjectMapValueType`: result += ` ${mm.type.name}`; break; case `${concerto_metamodel_1.MetaModelNamespace}.RelationshipProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.RelationshipMapValueType`: result += ` ${mm.type.name}`; break; } return result; } /** * Create modifiers string from a metamodel * * @param {object} mm - the metamodel * @return {string} the string for the modifiers */ function modifiersFromMetaModel(mm) { let result = ''; let defaultString = ''; let validatorString = ''; switch (mm.$class) { case `${concerto_metamodel_1.MetaModelNamespace}.EnumProperty`: break; case `${concerto_metamodel_1.MetaModelNamespace}.BooleanProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.BooleanScalar`: if (mm.defaultValue === true || mm.defaultValue === false) { if (mm.defaultValue) { defaultString += ' default=true'; } else { defaultString += ' default=false'; } } break; case `${concerto_metamodel_1.MetaModelNamespace}.DateTimeProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.DateTimeScalar`: if (mm.defaultValue) { defaultString += ` default="${mm.defaultValue}"`; } break; case `${concerto_metamodel_1.MetaModelNamespace}.DoubleProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.DoubleScalar`: if (mm.defaultValue !== undefined) { const doubleString = toDoubleString(mm.defaultValue); defaultString += ` default=${doubleString}`; } if (mm.validator) { const lowerString = mm.validator.lower !== undefined ? toDoubleString(mm.validator.lower) : ''; const upperString = mm.validator.upper !== undefined ? toDoubleString(mm.validator.upper) : ''; validatorString += ` range=[${lowerString},${upperString}]`; } break; case `${concerto_metamodel_1.MetaModelNamespace}.IntegerProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.IntegerScalar`: if (mm.defaultValue !== undefined) { defaultString += ` default=${mm.defaultValue.toString()}`; } if (mm.validator) { const lowerString = mm.validator.lower !== undefined ? mm.validator.lower : ''; const upperString = mm.validator.upper !== undefined ? mm.validator.upper : ''; validatorString += ` range=[${lowerString},${upperString}]`; } break; case `${concerto_metamodel_1.MetaModelNamespace}.LongProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.LongScalar`: if (mm.defaultValue !== undefined) { defaultString += ` default=${mm.defaultValue.toString()}`; } if (mm.validator) { const lowerString = mm.validator.lower !== undefined ? mm.validator.lower : ''; const upperString = mm.validator.upper !== undefined ? mm.validator.upper : ''; validatorString += ` range=[${lowerString},${upperString}]`; } break; case `${concerto_metamodel_1.MetaModelNamespace}.StringProperty`: case `${concerto_metamodel_1.MetaModelNamespace}.StringScalar`: if (mm.defaultValue) { defaultString += ` default="${mm.defaultValue}"`; } if (mm.validator) { validatorString += ` regex=/${mm.validator.pattern}/${mm.validator.flags || ''}`; } if (mm.lengthValidator) { const minLength = mm.lengthValidator.minLength !== undefined ? mm.lengthValidator.minLength : ''; const maxLength = mm.lengthValidator.maxLength !== undefined ? mm.lengthValidator.maxLength : ''; validatorString += ` length=[${minLength},${maxLength}]`; } break; case `${concerto_metamodel_1.MetaModelNamespace}.ObjectProperty`: if (mm.defaultValue) { defaultString += ` default="${mm.defaultValue}"`; } break; } return result + defaultString + validatorString; } /** * Format a numeric literal as a Double token for CTO output. * @param {number} value - numeric value to format * @returns {string} CTO-compatible Double literal */ function toDoubleString(value) { const normalizedValue = Number(value).toLocaleString('en-US', { useGrouping: false, // Intl.NumberFormat permits 1..21; use the maximum to avoid exponent output. maximumSignificantDigits: 21, }); if (!normalizedValue.includes('.')) { return `${normalizedValue}.0`; } return normalizedValue; } /** * Create property string from a metamodel * * @param {object} prop - the property metamodel object * @return {string} the string for the property */ function propertyFromMetaModel(prop) { let result = ''; if (prop.decorators) { result += decoratorsFromMetaModel(prop.decorators, ' '); } if (prop.$class === `${concerto_metamodel_1.MetaModelNamespace}.RelationshipProperty`) { result += '-->'; } else { result += 'o'; } result += typeFromMetaModel(prop); if (prop.isArray) { result += '[]'; } result += ` ${prop.name}`; result += modifiersFromMetaModel(prop); if (prop.isOptional) { result += ' optional'; } return result; } /** * Create map type string from a metamodel map * * @param {object} entry - the map metamodel object * @return {string} the string for the map */ function mapFromMetaModel(entry) { let result = ''; if (entry.decorators) { result += decoratorsFromMetaModel(entry.decorators, ' '); } if (entry.$class === `${concerto_metamodel_1.MetaModelNamespace}.RelationshipMapValueType`) { result += '-->'; } else { result += 'o'; } result += typeFromMetaModel(entry); return result; } /** * Create declaration string from a metamodel * * @param {object} mm - the declaration metamodel object * @return {string} the string for the declaration */ function declFromMetaModel(mm) { let result = ''; if (mm.decorators) { result += decoratorsFromMetaModel(mm.decorators, ''); } if (isScalar(mm)) { result += `scalar ${mm.name} extends`; result += typeFromMetaModel(mm); result += modifiersFromMetaModel(mm); } else if (isMap(mm)) { result += `map ${mm.name} {`; const mapDecl = mm; result += `\n ${mapFromMetaModel(mapDecl.key)}`; result += `\n ${mapFromMetaModel(mapDecl.value)}`; result += '\n}'; } else { const conceptDecl = mm; if (conceptDecl.isAbstract) { result += 'abstract '; } switch (mm.$class) { case `${concerto_metamodel_1.MetaModelNamespace}.AssetDeclaration`: result += `asset ${mm.name} `; break; case `${concerto_metamodel_1.MetaModelNamespace}.ConceptDeclaration`: result += `concept ${mm.name} `; break; case `${concerto_metamodel_1.MetaModelNamespace}.EventDeclaration`: result += `event ${mm.name} `; break; case `${concerto_metamodel_1.MetaModelNamespace}.ParticipantDeclaration`: result += `participant ${mm.name} `; break; case `${concerto_metamodel_1.MetaModelNamespace}.TransactionDeclaration`: result += `transaction ${mm.name} `; break; case `${concerto_metamodel_1.MetaModelNamespace}.EnumDeclaration`: result += `enum ${mm.name} `; break; } // Handle identified if (conceptDecl.identified) { if (conceptDecl.identified.$class === `${concerto_metamodel_1.MetaModelNamespace}.IdentifiedBy`) { const identifiedBy = conceptDecl.identified; result += `identified by ${identifiedBy.name} `; } else { result += 'identified '; } } // Handle supertype if (conceptDecl.superType) { if (conceptDecl.superType.name === mm.name) { throw new Error(`The declaration "${mm.name}" cannot extend itself.`); } result += `extends ${conceptDecl.superType.name} `; } result += '{'; // Handle properties conceptDecl.properties.forEach((property) => { result += `\n ${propertyFromMetaModel(property)}`; }); result += '\n}'; } return result; } /** * Converts a metamodel instance to a CTO string * * @param {*} metaModel - the metamodel instance * @return {string} the CTO model as a string */ function toCTO(metaModel) { let result = ''; // version if (metaModel.concertoVersion) { result += `concerto version "${metaModel.concertoVersion}"\n\n`; } // decorators if (metaModel.decorators && metaModel.decorators.length > 0) { result += decoratorsFromMetaModel(metaModel.decorators, ''); } // namespace result += `namespace ${metaModel.namespace}`; // imports if (metaModel.imports && metaModel.imports.length > 0) { result += '\n'; metaModel.imports.forEach((imp) => { switch (imp.$class) { case `${concerto_metamodel_1.MetaModelNamespace}.ImportType`: case `${concerto_metamodel_1.MetaModelNamespace}.ImportTypeFrom`: { const typedImport = imp; result += `\nimport ${imp.namespace}.${typedImport.name}`; break; } case `${concerto_metamodel_1.MetaModelNamespace}.ImportAll`: case `${concerto_metamodel_1.MetaModelNamespace}.ImportAllFrom`: result += `\nimport ${imp.namespace}.*`; break; case `${concerto_metamodel_1.MetaModelNamespace}.ImportTypes`: { const typesImport = imp; const aliasedTypes = typesImport.aliasedTypes ? new Map(typesImport.aliasedTypes.map((aliasedType) => [ aliasedType.name, aliasedType.aliasedName, ])) : new Map(); const commaSeparatedTypesString = typesImport.types .map((type) => aliasedTypes.has(type) ? `${type} as ${aliasedTypes.get(type)}` : type) .join(','); result += `\nimport ${imp.namespace}.{${commaSeparatedTypesString}}`; break; } default: throw new Error('Unrecognized import'); } if (imp.uri) { result += ` from ${imp.uri}`; } }); } // declarations if (metaModel.declarations && metaModel.declarations.length > 0) { metaModel.declarations.forEach((decl) => { result += `\n\n${declFromMetaModel(decl)}`; }); } return result; } module.exports = { toCTO, }; //# sourceMappingURL=printer.js.map