From ed6bef693d0eba2f4bcbc2cd70e535fc16e1cbf4 Mon Sep 17 00:00:00 2001 From: RaviChauhan <1chauhanravi0@gmail.com> Date: Sun, 1 Mar 2026 16:29:43 +0530 Subject: [PATCH] fix: align vocabulary handling with concerto-vocabulary@3.x and restore correct transform pipeline --- concerto | 1 + eslint.config.mjs | 13 +- package-lock.json | 209 ++- package.json | 10 +- src/TemplateArchiveProcessor.ts | 338 +++-- src/TemplateMarkInterpreter.ts | 1290 ++++++++++------- src/TypeScriptRuntime.ts | 10 +- src/runtime/declarations.ts | 2 +- test/Vocabulary.test.ts | 69 + .../CustomTemplateModel.test.ts.snap | 2 + .../GenerateOptions.test.ts.snap | 1 + test/__snapshots__/HelloWorld.test.ts.snap | 1 + .../TemplateMarkInterpreter.test.ts.snap | 81 ++ 13 files changed, 1279 insertions(+), 748 deletions(-) create mode 160000 concerto create mode 100644 test/Vocabulary.test.ts diff --git a/concerto b/concerto new file mode 160000 index 0000000..0af6042 --- /dev/null +++ b/concerto @@ -0,0 +1 @@ +Subproject commit 0af60427ff389666e5eacbf810ba67278f12ab95 diff --git a/eslint.config.mjs b/eslint.config.mjs index 8e87cb6..11f68c9 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -4,16 +4,25 @@ import js from "@eslint/js"; import tseslint from "typescript-eslint"; export default defineConfig([ - globalIgnores(["dist/", "scripts/", "**/model-gen/**"]), + globalIgnores([ + "dist/", + "scripts/", + "**/model-gen/**", + "concerto/**" + ]), + { files: ["**/*.{js,mjs,cjs,ts}"] }, + { files: ["**/*.{js,mjs,cjs,ts}"], languageOptions: { globals: { ...globals.browser, ...globals.node } }, }, + { files: ["**/*.{js,mjs,cjs,ts}"], plugins: { js }, extends: ["js/recommended"], }, + tseslint.configs.recommended, -]); +]); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ab0a77f..991a784 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@accordproject/concerto-codegen": "3.30.6-20250327205534", "@accordproject/concerto-core": "^3.20.4", "@accordproject/concerto-util": "^3.20.4", + "@accordproject/concerto-vocabulary": "^3.25.7", "@accordproject/markdown-common": "0.16.25", "@accordproject/markdown-template": "0.16.25", "@typescript/twoslash": "^3.2.9", @@ -48,7 +49,7 @@ "rollup-plugin-dts": "^6.2.1", "rollup-plugin-esbuild": "^6.2.1", "terser": "^5.39.0", - "ts-jest": "^29.3.0", + "ts-jest": "^29.4.6", "ts-node": "^10.9.2", "typescript-eslint": "^8.28.0" }, @@ -182,6 +183,20 @@ } } }, + "node_modules/@accordproject/concerto-codegen/node_modules/@accordproject/concerto-vocabulary": { + "version": "3.20.3", + "resolved": "https://registry.npmjs.org/@accordproject/concerto-vocabulary/-/concerto-vocabulary-3.20.3.tgz", + "integrity": "sha512-tzKk0HUP8JlBN/3ZQWu+8/3viPu3Z/NgTuC1qOa4nRSOwm3WTw6caVp7c6PzgOR/AZ3184VOd+qaihzkK7TQcA==", + "license": "Apache-2.0", + "dependencies": { + "@accordproject/concerto-metamodel": "3.11.0", + "yaml": "2.6.1" + }, + "engines": { + "node": ">=18", + "npm": ">=10" + } + }, "node_modules/@accordproject/concerto-codegen/node_modules/ms": { "version": "2.1.3", "license": "MIT" @@ -196,6 +211,18 @@ "node": ">=10" } }, + "node_modules/@accordproject/concerto-codegen/node_modules/yaml": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", + "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@accordproject/concerto-core": { "version": "3.20.4", "license": "Apache-2.0", @@ -298,17 +325,29 @@ "license": "MIT" }, "node_modules/@accordproject/concerto-vocabulary": { - "version": "3.20.3", + "version": "3.25.7", + "resolved": "https://registry.npmjs.org/@accordproject/concerto-vocabulary/-/concerto-vocabulary-3.25.7.tgz", + "integrity": "sha512-C/HAqvskqzSZxGNWSFN93Y7U9efcQexEVjRK7UAyQUBbkNVZWdLNCHoYrFK995r5t9NUEqnsoAigO8Rv1mhZ2Q==", "license": "Apache-2.0", "dependencies": { - "@accordproject/concerto-metamodel": "3.11.0", - "yaml": "2.6.1" + "@accordproject/concerto-metamodel": "3.12.6", + "yaml": "2.8.0" }, "engines": { "node": ">=18", "npm": ">=10" } }, + "node_modules/@accordproject/concerto-vocabulary/node_modules/@accordproject/concerto-metamodel": { + "version": "3.12.6", + "resolved": "https://registry.npmjs.org/@accordproject/concerto-metamodel/-/concerto-metamodel-3.12.6.tgz", + "integrity": "sha512-GGkD5H89dUt4Z6CyP+ozFMYEYrKyCq9QHYV3DcyyJY9q3tGGr+elvGJqUoC20ljZaE6HV0GPar54GTMDEmh6pw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14", + "npm": ">=6" + } + }, "node_modules/@accordproject/markdown-cicero": { "version": "0.16.25", "license": "Apache-2.0", @@ -3504,6 +3543,8 @@ }, "node_modules/@types/jest": { "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3999,11 +4040,6 @@ "node": ">=0.8" } }, - "node_modules/async": { - "version": "3.2.6", - "dev": true, - "license": "MIT" - }, "node_modules/async-function": { "version": "1.0.0", "license": "MIT", @@ -4950,20 +4986,6 @@ "safer-buffer": "^2.1.0" } }, - "node_modules/ejs": { - "version": "3.1.10", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/electron-to-chromium": { "version": "1.5.128", "dev": true, @@ -5581,33 +5603,6 @@ "node": ">=16.0.0" } }, - "node_modules/filelist": { - "version": "1.0.4", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/fill-range": { "version": "7.1.1", "dev": true, @@ -5989,6 +5984,28 @@ "dev": true, "license": "MIT" }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/har-schema": { "version": "2.0.0", "license": "ISC", @@ -6844,23 +6861,6 @@ "node": ">=8" } }, - "node_modules/jake": { - "version": "10.9.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest": { "version": "29.7.0", "dev": true, @@ -8064,6 +8064,16 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "4.2.8", "dev": true, @@ -8132,6 +8142,13 @@ "dev": true, "license": "MIT" }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, "node_modules/next-tick": { "version": "0.2.2", "license": "MIT" @@ -10309,19 +10326,20 @@ } }, "node_modules/ts-jest": { - "version": "29.3.0", + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", + "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", "dev": true, "license": "MIT", "dependencies": { "bs-logger": "^0.2.6", - "ejs": "^3.1.10", "fast-json-stable-stringify": "^2.1.0", - "jest-util": "^29.0.0", + "handlebars": "^4.7.8", "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", - "semver": "^7.7.1", - "type-fest": "^4.37.0", + "semver": "^7.7.3", + "type-fest": "^4.41.0", "yargs-parser": "^21.1.1" }, "bin": { @@ -10332,10 +10350,11 @@ }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", "typescript": ">=4.3 <6" }, "peerDependenciesMeta": { @@ -10353,11 +10372,16 @@ }, "esbuild": { "optional": true + }, + "jest-util": { + "optional": true } } }, "node_modules/ts-jest/node_modules/semver": { - "version": "7.7.1", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -10368,7 +10392,9 @@ } }, "node_modules/ts-jest/node_modules/type-fest": { - "version": "4.38.0", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -10601,6 +10627,20 @@ "version": "1.0.6", "license": "MIT" }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/unbox-primitive": { "version": "1.1.0", "license": "MIT", @@ -11028,6 +11068,13 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "7.0.0", "license": "MIT", @@ -11189,13 +11236,15 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.6.1", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" + "node": ">= 14.6" } }, "node_modules/yargs": { diff --git a/package.json b/package.json index 71bc5de..7ea5170 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ "pretest": "npm-run-all licchk lint build", "lint": "eslint .", "licchk": "license-check-and-add", - "test": "node --experimental-vm-modules node_modules/.bin/jest", - "coverage": "node --experimental-vm-modules node_modules/.bin/jest --coverage", + "test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js", + "coverage": "jest --coverage", "test:watch": "jest --watchAll", "updateRuntimeDependencies": "node ./scripts/updateRuntimeDependencies" }, @@ -43,6 +43,7 @@ "@accordproject/concerto-codegen": "3.30.6-20250327205534", "@accordproject/concerto-core": "^3.20.4", "@accordproject/concerto-util": "^3.20.4", + "@accordproject/concerto-vocabulary": "^3.25.7", "@accordproject/markdown-common": "0.16.25", "@accordproject/markdown-template": "0.16.25", "@typescript/twoslash": "^3.2.9", @@ -78,7 +79,7 @@ "rollup-plugin-dts": "^6.2.1", "rollup-plugin-esbuild": "^6.2.1", "terser": "^5.39.0", - "ts-jest": "^29.3.0", + "ts-jest": "^29.4.6", "ts-node": "^10.9.2", "typescript-eslint": "^8.28.0" }, @@ -131,7 +132,8 @@ "testPathIgnorePatterns": [ "/dist/", "/node_modules/", - "/scripts" + "/scripts", + "/concerto/" ], "collectCoverage": false, "collectCoverageFrom": [ diff --git a/src/TemplateArchiveProcessor.ts b/src/TemplateArchiveProcessor.ts index 3fd8f56..66077ac 100644 --- a/src/TemplateArchiveProcessor.ts +++ b/src/TemplateArchiveProcessor.ts @@ -14,171 +14,211 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Template } from '@accordproject/cicero-core'; -import { TemplateMarkInterpreter } from './TemplateMarkInterpreter'; -import { TemplateMarkTransformer } from '@accordproject/markdown-template'; -import { transform } from '@accordproject/markdown-transform'; -import { TypeScriptToJavaScriptCompiler } from './TypeScriptToJavaScriptCompiler'; -import Script from '@accordproject/cicero-core/types/src/script'; -import { TwoSlashReturn } from '@typescript/twoslash'; -import { JavaScriptEvaluator } from './JavaScriptEvaluator'; -import { SMART_LEGAL_CONTRACT_BASE64 } from './runtime/declarations'; +import { Template } from "@accordproject/cicero-core"; +import { TemplateMarkInterpreter } from "./TemplateMarkInterpreter"; +import { TemplateMarkTransformer } from "@accordproject/markdown-template"; +import { transform } from "@accordproject/markdown-transform"; +import { TypeScriptToJavaScriptCompiler } from "./TypeScriptToJavaScriptCompiler"; +import Script from "@accordproject/cicero-core/types/src/script"; +import { TwoSlashReturn } from "@typescript/twoslash"; +import { JavaScriptEvaluator } from "./JavaScriptEvaluator"; +import { SMART_LEGAL_CONTRACT_BASE64 } from "./runtime/declarations"; export type State = object; export type Response = object; export type Event = object; export type TriggerResponse = { - result: Response; - state: State; - events: Event[]; -} + result: Response; + state: State; + events: Event[]; +}; export type InitResponse = { - state: State; -} + state: State; +}; /** * A template archive processor: can draft content using the * templatemark for the archive and trigger the logic of the archive */ export class TemplateArchiveProcessor { - template: Template; - - /** - * Creates a template archive processor - * @param {Template} template - the template to be used by the processor - */ - constructor(template: Template) { - this.template = template; - } - - /** - * Drafts a template by merging it with data - * @param {any} data the data to merge with the template - * @param {string} format the output format - * @param {any} options merge options - * @param {[string]} currentTime the current value for 'now' - * @returns {Promise} the drafted content - */ - async draft(data: any, format: string, options: any, currentTime?: string): Promise { - // Setup - const metadata = this.template.getMetadata(); - const templateKind = metadata.getTemplateType() !== 0 ? 'clause' : 'contract'; - - // Get the data - const modelManager = this.template.getModelManager(); - const engine = new TemplateMarkInterpreter(modelManager, {}); - const templateMarkTransformer = new TemplateMarkTransformer(); - const templateMarkDom = templateMarkTransformer.fromMarkdownTemplate( - { content: this.template.getTemplate() }, modelManager, templateKind, {options}); - const now = currentTime ? currentTime : new Date().toISOString(); - // console.log(JSON.stringify(templateMarkDom, null, 2)); - const ciceroMark = await engine.generate(templateMarkDom, data, { now }); - // console.log(JSON.stringify(ciceroMark)); - const result = transform(ciceroMark.toJSON(), 'ciceromark', ['ciceromark_unquoted', format], null, options); - // console.log(result); - return result; - + template: Template; + + /** + * Creates a template archive processor + * @param {Template} template - the template to be used by the processor + */ + constructor(template: Template) { + this.template = template; + } + + /** + * Drafts a template by merging it with data + * @param {any} data the data to merge with the template + * @param {string} format the output format + * @param {any} options merge options + * @param {[string]} currentTime the current value for 'now' + * @returns {Promise} the drafted content + */ + async draft( + data: any, + format: string, + options: any, + currentTime?: string, + ): Promise { + // Setup + const metadata = this.template.getMetadata(); + const templateKind = + metadata.getTemplateType() !== 0 ? "clause" : "contract"; + + // Get the data + const modelManager = this.template.getModelManager(); + const engine = new TemplateMarkInterpreter(modelManager, {}); + const templateMarkTransformer = new TemplateMarkTransformer(); + const templateMarkDom = templateMarkTransformer.fromMarkdownTemplate( + { content: this.template.getTemplate() }, + modelManager, + templateKind, + { options }, + ); + const now = currentTime ? currentTime : new Date().toISOString(); + // console.log(JSON.stringify(templateMarkDom, null, 2)); + const ciceroMark = await engine.generate(templateMarkDom, data, { now }); + // console.log(JSON.stringify(ciceroMark)); + const result = transform( + ciceroMark.toJSON(), + "ciceromark", + ["ciceromark_unquoted", format], + null, + options, + ); + + // Ensure CommonMark Document always has nodes array + if (result && typeof result === "object" && !result.nodes) { + result.nodes = []; } - /** - * Trigger the logic of a template - * @param {object} request - the request to send to the template logic - * @param {object} state - the current state of the template - * @param {[string]} currentTime - the current time, defaults to now - * @param {[number]} utcOffset - the UTC offer, defaults to zero - * @returns {Promise} the response and any events - */ - async trigger(data: any, request: any, state?: any, currentTime?: string, utcOffset?: number): Promise { - const logicManager = this.template.getLogicManager(); - if(logicManager.getLanguage() === 'typescript') { - const compiledCode:Record = {}; - const tsFiles:Array