Skip to content

Commit 271ceaa

Browse files
authored
feat(concertino): optimize format and built target (#1048)
* feat(concertino): optimize format and built target Signed-off-by: mttrbrts <[email protected]> * docs(README): add replit link Signed-off-by: mttrbrts <[email protected]> --------- Signed-off-by: mttrbrts <[email protected]>
1 parent 467b939 commit 271ceaa

File tree

13 files changed

+69
-3659
lines changed

13 files changed

+69
-3659
lines changed

packages/concertino/README.md

Lines changed: 38 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
Concertino is a lightweight variant of the Concerto metamodel format, optimized for client applications that need to programmatically introspect declarations without taking a dependency on the full Concerto SDK.
44

5+
## Benefits of the Concertino Format
6+
The Concertino format provides several advantages:
7+
8+
- Flatter structure: By denormalizing the inheritance hierarchy, consumers don't need to traverse the hierarchy to understand a definition.
9+
10+
- More explicit metadata: Additional metadata makes it clearer how properties should be interpreted.
11+
12+
- Ready for consumption: The transformation prepares the data for easier consumption by tools and renderers, without requiring additional processing.
13+
514
## Features
615

716
- **Fully Resolved Type References**: No ambiguous shortnames
@@ -10,14 +19,10 @@ Concertino is a lightweight variant of the Concerto metamodel format, optimized
1019
- **Extended Inheritance Chain**: Concepts list their full inheritance chain, not just immediate parent
1120
- **Scalar Type Denormalization**: For convenience in client applications
1221
- **Strict Mode By Default**: Namespaces are always versioned.
22+
- **Support for Partial Models** Allowing client applications to filter models to tailor payloads for their use cases.
23+
- **Lossless Conversion** Concertino is designed for 100% lossless roundtrip conversion with Concerto models.
1324

14-
## Lossless Conversion
15-
16-
Concertino is designed for 100% lossless roundtrip conversion:
17-
18-
Concerto (Metamodel) → Concertino → Concerto (Metamodel)
19-
20-
Note that namespaces in the source Concerto model should be fully resolved (including for local type references).
25+
> Concerto (Metamodel) → Concertino → Concerto (Metamodel)
2126
2227
## Installation
2328

@@ -29,37 +34,39 @@ npm install @accordproject/concertino
2934

3035
### Using the ConcertinoConverter Class
3136

37+
[Try it in Replit](https://replit.com/@mttrbrts/AccordProjectConcertino?v=1)
3238
```javascript
39+
const { ModelManager } = require('@accordproject/concerto-core');
3340
const { ConcertinoConverter } = require('@accordproject/concertino');
3441

35-
// Create a converter with custom options
36-
const converter = new ConcertinoConverter({
37-
version: '0.1.0-alpha.3' // Specify concertino version
38-
});
42+
// Prepare the Concerto model
43+
const mm = new ModelManager();
44+
mm.addModel(MODEL_FILE_CONTENTS);
45+
const model = mm.getModelFile(MODEL_FILE_NAMESPACE).getAst();
46+
47+
// Initialize Concertino
48+
const converter = new ConcertinoConverter();
49+
const models = { models: [model] };
3950

4051
// Convert from Concerto metamodel to Concertino
41-
const concertino = converter.fromConcertoMetamodel(concertoMetamodel);
52+
const concertino = converter.fromConcertoMetamodel(models);
53+
console.log('#### Concertino:')
54+
console.log(JSON.stringify(concertino, null, 2));
55+
console.log();
4256

4357
// Convert from Concertino back to Concerto metamodel
4458
const metamodel = converter.toConcertoMetamodel(concertino);
45-
59+
console.log('#### Concerto AST (Full Metamodel Instance):')
60+
console.log(JSON.stringify(metamodel, null, 2));
4661
```
4762

48-
### Using Individual Functions
49-
50-
```javascript
51-
const { convertToConcertino, convertToMetamodel } = require('@accordproject/concertino');
52-
53-
// Convert from Concerto metamodel to Concertino
54-
const concertino = convertToConcertino(concertoMetamodel);
63+
## Model Size
5564

56-
// Convert from Concertino back to Concerto metamodel
57-
const metamodel = convertToMetamodel(concertino);
58-
```
65+
Despite the denormalization of metadata, the JSON serialization of Concertino models are often smaller in size than their Concerto AST equivalents due to a flatter, dictionary-like design and the removal of type-discriminators (i.e. `$class` properties).
5966

60-
## File Size Reduction
67+
It is expected that models that make heavy use of inheritance would be larger than their equivalent Concerto AST.
6168

62-
Basic testing with pretty-printed, uncompressed files shows a 70-80% reduction in file size without loss of expressiveness.
69+
Note that when converting models, the namespaces in the source Concerto model should be fully resolved (including for local type references).
6370

6471
## Example Concertino JSON Format
6572

@@ -69,36 +76,27 @@ Below is an example of how a simple Concerto model is represented in the Concert
6976
{
7077
"declarations": {
7178
72-
"name": {
73-
"localName": "Address",
74-
"namespace": "readme",
75-
"version": "1.0.0",
76-
},
7779
"properties": {
7880
"city": {
7981
"name": "city",
80-
"scalarType": "String",
8182
"type": "String",
8283
"vocabulary": {
8384
"label": "City/Town",
8485
},
8586
},
8687
"country": {
8788
"name": "country",
88-
"scalarType": "String",
8989
"type": "String",
9090
},
9191
"street": {
9292
"name": "street",
93-
"scalarType": "String",
9493
"type": "String",
9594
"vocabulary": {
9695
"label": "Street Address",
9796
},
9897
},
9998
"zipCode": {
10099
"name": "zipCode",
101-
"scalarType": "String",
102100
"type": "String",
103101
},
104102
},
@@ -108,20 +106,10 @@ Below is an example of how a simple Concerto model is represented in the Concert
108106
},
109107
},
110108
111-
"name": {
112-
"localName": "Email",
113-
"namespace": "readme",
114-
"version": "1.0.0",
115-
},
116109
"regex": "/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/",
117110
"type": "StringScalar",
118111
},
119112
120-
"name": {
121-
"localName": "Person",
122-
"namespace": "readme",
123-
"version": "1.0.0",
124-
},
125113
"properties": {
126114
"address": {
127115
"isOptional": true,
@@ -138,7 +126,6 @@ Below is an example of how a simple Concerto model is represented in the Concert
138126
0,
139127
null,
140128
],
141-
"scalarType": "Integer",
142129
"type": "Integer",
143130
},
144131
"email": {
@@ -153,15 +140,13 @@ Below is an example of how a simple Concerto model is represented in the Concert
153140
},
154141
"firstName": {
155142
"name": "firstName",
156-
"scalarType": "String",
157143
"type": "String",
158144
"vocabulary": {
159145
"label": "Given Name",
160146
},
161147
},
162148
"lastName": {
163149
"name": "lastName",
164-
"scalarType": "String",
165150
"type": "String",
166151
"vocabulary": {
167152
"label": "Family Name",
@@ -178,7 +163,7 @@ Below is an example of how a simple Concerto model is represented in the Concert
178163
},
179164
},
180165
"metadata": {
181-
"concertinoVersion": "0.1.0-alpha.3",
166+
"concertinoVersion": "1.0.0-alpha.7",
182167
"models": {
183168
184169
"concertoVersion": "1.0.0",
@@ -194,23 +179,15 @@ Below is an example of how a simple Concerto model is represented in the Concert
194179
}
195180
}
196181
```
197-
```
198-
199-
This example demonstrates how Concertino represents:
200-
201-
1. Fully qualified type names as object keys
202-
2. Denormalized properties with their constraints
203-
3. Flattened declarations outside of their model nesting
204-
4. Metadata including versioning information
205-
5. Decorators at the model, concept, and property level
206-
6. Vocabulary with labels and additional terms
207182

208183
The equivalent Concerto CTO file would be:
209184

210-
```cto
185+
```cs
211186
@license("Apache-2.0")
212187
namespace org.example.models@1.0.0
213188

189+
scalar Email extends String regex=/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
190+
214191
@Term("Individual")
215192
@Term_plural("People")
216193
concept Person {
@@ -220,10 +197,10 @@ concept Person {
220197
@Term("Family Name")
221198
o String lastName
222199

223-
o Integer age optional range=[0, 120]
200+
o Integer age optional range=[0, ]
224201

225202
@sensitive
226-
o String email optional regex=/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
203+
o Email email optional
227204

228205
@Term("Mailing Address")
229206
o Address address optional

packages/concertino/package-lock.json

Lines changed: 5 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/concertino/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@accordproject/concertino",
3-
"version": "1.0.0-alpha.3",
3+
"version": "1.0.0-alpha.7",
44
"description": "Object-centric serialization of Concerto models",
55
"homepage": "https://github.com/accordproject/concerto",
66
"engines": {
@@ -11,13 +11,14 @@
1111
"typings": "dist/index.d.ts",
1212
"scripts": {
1313
"clean": "rimraf dist",
14-
"prebuild": "npm-run-all clean",
14+
"prebuild": "npm-run-all clean generate-types",
1515
"build": "tsc -p tsconfig.build.json",
16+
"postbuild": "cp -R src/spec/*.json dist/spec/",
1617
"pretest": "#npm-run-all lint",
1718
"lint": "eslint .",
1819
"test": "vitest run",
1920
"test:watch": "vitest",
20-
"generate-types": "ENABLE_MAP_TYPE=true node --experimental-modules scripts/generateTypes.js"
21+
"generate-types": "ENABLE_MAP_TYPE=true node scripts/generateTypes.js"
2122
},
2223
"repository": {
2324
"type": "git",
@@ -31,21 +32,20 @@
3132
],
3233
"author": "accordproject.org",
3334
"license": "Apache-2.0",
34-
"type": "module",
3535
"dependencies": {
3636
"@accordproject/concerto-core": "3.22.0",
37-
"@accordproject/concerto-types": "3.22.0",
37+
"ajv": "^8.17.1",
3838
"semver": "7.6.3"
3939
},
4040
"devDependencies": {
41+
"@accordproject/concerto-types": "3.22.0",
4142
"@accordproject/concerto-codegen": "^3.22.0",
4243
"@accordproject/concerto-cto": "3.22.0",
4344
"@accordproject/concerto-util": "^3.22.0",
4445
"@types/semver": "7.5.8",
4546
"@typescript-eslint/eslint-plugin": "8.16.0",
4647
"@typescript-eslint/parser": "8.16.0",
4748
"@vitest/coverage-v8": "^3.2.4",
48-
"ajv": "^8.17.1",
4949
"eslint": "8.57.1",
5050
"npm-run-all": "4.1.5",
5151
"typescript": "^5.7.2",

packages/concertino/scripts/generateTypes.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable @typescript-eslint/no-require-imports */
12
/*
23
* Licensed under the Apache License, Version 2.0 (the "License");
34
* you may not use this file except in compliance with the License.
@@ -12,16 +13,13 @@
1213
* limitations under the License.
1314
*/
1415

15-
import fs from 'fs';
16-
import path from 'path';
17-
import { ModelManager, ModelUtil } from '@accordproject/concerto-core';
18-
import { FileWriter } from '@accordproject/concerto-util';
19-
import { CodeGen } from '@accordproject/concerto-codegen';
20-
import { fileURLToPath } from 'url';
16+
'use strict';
2117

22-
// Get the directory name of the current module
23-
const __filename = fileURLToPath(import.meta.url);
24-
const __dirname = path.dirname(__filename);
18+
const fs = require('fs');
19+
const path = require('path');
20+
const { ModelManager, ModelUtil } = require('@accordproject/concerto-core');
21+
const { FileWriter } = require('@accordproject/concerto-util');
22+
const { CodeGen } = require('@accordproject/concerto-codegen');
2523

2624
const OVERRIDE_DECORATOR = 'CodeGen_TypeScript_Override';
2725

0 commit comments

Comments
 (0)