diff --git a/README.md b/README.md index 68cfd07..9eb346b 100644 --- a/README.md +++ b/README.md @@ -33,11 +33,30 @@ Please visit the [Visual Studio Code Marketplace](https://marketplace.visualstud ### Commands +- Compile your ``model.cto `` file to a target + +![Code Gen GIF](./assets/Code%20Gen.gif) + + +- Draft clause after passing relevent input into the form. + +![Draft Clause GIF](./assets/Draft%20Clause.gif) + + - Work offline by downloading Concerto model dependencies (context-click on a `*.cto` file) -- Package templates into Cicero Template Archive (cta) files (context-click on root folder) - Export PlantUML class diagram (context-click on a `*.cto` file) + +![Downdload Models and Export Class Diagrsms GIF](./assets/Downloads%20Models%20and%20Export%20Class%20Diagrsm.gif) + +- Parse Clause after entering relevent information into the input form. +- Export the template directory as a ``.cta`` archive. + + ![Parse Clause and Export as archive GIF](./assets/Parse%20Clause%20And%20Export%20As%20Archive.gif) + - Trigger a template, parsing data from sample.md and passing in `request.json` and `state.json` (context-click on root folder) +![Trigger Clause GIF](./assets/Trigger%20Clause.gif) + ### Views - HTML preview for template text (open `grammar.tem.md` and then press the _Open Preview_ icon in the editor or context menu) - HTML preview for Concerto models (open `*.cto` and then press the _Open Preview_ icon in the editor or context menu) diff --git a/assets/Code Gen.gif b/assets/Code Gen.gif new file mode 100644 index 0000000..3635d6a Binary files /dev/null and b/assets/Code Gen.gif differ diff --git a/assets/Downloads Models and Export Class Diagrsm.gif b/assets/Downloads Models and Export Class Diagrsm.gif new file mode 100644 index 0000000..4e5fa30 Binary files /dev/null and b/assets/Downloads Models and Export Class Diagrsm.gif differ diff --git a/assets/Draft Clause.gif b/assets/Draft Clause.gif new file mode 100644 index 0000000..3c56941 Binary files /dev/null and b/assets/Draft Clause.gif differ diff --git a/assets/Parse Clause And Export As Archive.gif b/assets/Parse Clause And Export As Archive.gif new file mode 100644 index 0000000..d817a9b Binary files /dev/null and b/assets/Parse Clause And Export As Archive.gif differ diff --git a/assets/Trigger Clause.gif b/assets/Trigger Clause.gif new file mode 100644 index 0000000..efd0c16 Binary files /dev/null and b/assets/Trigger Clause.gif differ diff --git a/babel.config.json b/babel.config.json index 1cdfa65..37c4c07 100644 --- a/babel.config.json +++ b/babel.config.json @@ -3,5 +3,8 @@ "@babel/preset-env", "@babel/preset-typescript" ], - "plugins": ["@babel/plugin-transform-typescript"] + "plugins": ["@babel/plugin-transform-typescript",["@babel/plugin-transform-runtime", + { + "regenerator": true + }]] } \ No newline at end of file diff --git a/client/package-lock.json b/client/package-lock.json index c64ec4f..9b81efa 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -11,8 +11,8 @@ "dependencies": { "@accordproject/cicero-core": "^0.22.0", "@accordproject/cicero-engine": "^0.22.0", - "@accordproject/concerto-core": "^1.0.0", - "@accordproject/concerto-tools": "^1.0.0", + "@accordproject/concerto-core": "^1.2.1", + "@accordproject/concerto-tools": "^1.2.1", "@accordproject/markdown-it-cicero": "^0.13.0", "@accordproject/markdown-it-template": "^0.13.0", "mermaid": "^8.13.8", diff --git a/client/package.json b/client/package.json index c628051..ebd3f3f 100644 --- a/client/package.json +++ b/client/package.json @@ -21,8 +21,8 @@ "dependencies": { "@accordproject/cicero-core": "^0.22.0", "@accordproject/cicero-engine": "^0.22.0", - "@accordproject/concerto-core": "^1.0.0", - "@accordproject/concerto-tools": "^1.0.0", + "@accordproject/concerto-core": "^1.2.1", + "@accordproject/concerto-tools": "^1.2.1", "@accordproject/markdown-it-cicero": "^0.13.0", "@accordproject/markdown-it-template": "^0.13.0", "mermaid": "^8.13.8", diff --git a/client/src/extension.ts b/client/src/extension.ts index 17e5d97..0d5ef1c 100755 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -36,6 +36,8 @@ import { getPreviewWebviewContent, parseClause, setOutputChannelForCommonCommands, + draftClause, + compileToTarget, } from './webCommandHandlers'; let client: LanguageClient; @@ -123,7 +125,11 @@ export function activate(context: vscode.ExtensionContext) { .registerCommand('cicero-vscode-extension.parseClause', parseClause)); context.subscriptions.push(vscode.commands .registerCommand('cicero-vscode-extension.verifyTemplateSignature', verifyTemplateSignature)); - + context.subscriptions.push(vscode.commands + .registerCommand('cicero-vscode-extension.draftClause', draftClause)); + context.subscriptions.push(vscode.commands + .registerCommand('cicero-vscode-extension.compileToTarget', compileToTarget)); + let currentPanel: vscode.WebviewPanel | undefined = undefined; context.subscriptions.push( diff --git a/client/src/utils.ts b/client/src/utils.ts index 9189886..47ae897 100644 --- a/client/src/utils.ts +++ b/client/src/utils.ts @@ -69,7 +69,8 @@ async function loadFileBuffer(path, fileName, required=false) { const filePath = Utils.resolvePath(path, fileName); try{ - return await vscode.workspace.fs.readFile(filePath); + const contents = Buffer.from(await vscode.workspace.fs.readFile(filePath)); + return contents; } catch(e) { if(required){ @@ -117,8 +118,7 @@ export async function fromDirectory(Template, path, options = {offline:false}) { const readmeContents = await loadFileContents(path, 'README.md'); // grab the logo.png - const logo = Buffer.from(await loadFileBuffer(path, 'logo.png')); - + const logo = await loadFileBuffer(path, 'logo.png'); // grab the request.json const requestJsonObject = await loadFileContents(path, 'request.json', true ); diff --git a/client/src/webClientMain.ts b/client/src/webClientMain.ts index ec130d0..4094546 100644 --- a/client/src/webClientMain.ts +++ b/client/src/webClientMain.ts @@ -24,7 +24,9 @@ import { downloadModels, exportClassDiagram, parseClause, - exportArchive + exportArchive, + compileToTarget, + draftClause } from './webCommandHandlers'; async function onDocumentChange(event) { @@ -55,6 +57,10 @@ export async function activate(context: vscode.ExtensionContext) { .registerCommand('cicero-vscode-extension.downloadModels', downloadModels)); context.subscriptions.push(vscode.commands .registerCommand('cicero-vscode-extension.exportClassDiagram', exportClassDiagram)); + context.subscriptions.push(vscode.commands + .registerCommand('cicero-vscode-extension.compileToTarget', compileToTarget)); + context.subscriptions.push(vscode.commands + .registerCommand('cicero-vscode-extension.draftClause', draftClause)); let currentPanel: vscode.WebviewPanel | undefined = undefined; diff --git a/client/src/webCommandHandlers.ts b/client/src/webCommandHandlers.ts index 95069f4..c894607 100644 --- a/client/src/webCommandHandlers.ts +++ b/client/src/webCommandHandlers.ts @@ -101,6 +101,112 @@ async function getModelManager(ctoFile: vscode.Uri) { return null; } +export async function draftClause(file: vscode.Uri) { + try { + const templateDirectory = Utils.resolvePath(file,".."); + await vscode.workspace.saveAll(); + + var panel = vscode.window.createWebviewPanel( + 'draftInput', + 'Draft Input', + vscode.ViewColumn.Beside, + { + // Enable scripts in the webview + enableScripts: true + } + ); + + panel.webview.html = await getDraftWebviewContent(path.relative(templateDirectory.path,file.path)); + + panel.webview.onDidReceiveMessage( + async (message) => { + const {dataPath,outputPath,utcOffset,currentTime} = message; + outputChannel.show(); + const template = await fromDirectory(Template,templateDirectory); + const clause = new Clause(template); + + const clauseData = JSON.parse(Buffer.from(await vscode.workspace.fs.readFile(Utils.resolvePath(templateDirectory,dataPath.slice(1)))).toString()); + clause.setData(clauseData); + + const drafted = clause.draft(null, currentTime, utcOffset); + + outputChannel.show(); + + outputChannel.appendLine(`${dataPath} parse result`); + outputChannel.appendLine('======================'); + outputChannel.appendLine(drafted); + outputChannel.appendLine(''); + + await vscode.workspace.fs.writeFile( Utils.resolvePath(templateDirectory,outputPath), Buffer.from(drafted,'utf-8')); + outputChannel.appendLine(`Output written to ${outputPath}`); + outputChannel.appendLine(''); + }, + null + ) + + return true; + } catch (error) { + vscode.window.showErrorMessage( `Failed to draft clause ${error}`); + } + + return false; +} + +export async function compileToTarget(file: vscode.Uri) { + try{ + const modelManager = await getModelManager(file); + + const targets = await vscode.window.showQuickPick(['Go', 'PlantUML', 'JSONSchema', 'Typescript', 'Java', 'XMLSchema', 'GraphQL', 'CSharp'],{canPickMany:true}) + + for(const target of targets){ + let visitor = null; + const outputPath = Utils.resolvePath(Utils.dirname(file),target); + + switch(target) { + case 'Go': + visitor = new CodeGen.GoLangVisitor(); + break; + case 'PlantUML': + visitor = new CodeGen.PlantUMLVisitor(); + break; + case 'Typescript': + visitor = new CodeGen.TypescriptVisitor(); + break; + case 'Java': + visitor = new CodeGen.JavaVisitor(); + break; + case 'JSONSchema': + visitor = new CodeGen.JSONSchemaVisitor(); + break; + case 'XMLSchema': + visitor = new CodeGen.XmlSchemaVisitor(); + break; + case 'GraphQL': + visitor = new CodeGen.GraphQLVisitor(); + break; + case 'CSharp': + visitor = new CodeGen.CSharpVisitor(); + break; + case 'OData': + visitor = new CodeGen.ODataVisitor(); + break; + } + + if(visitor) { + let parameters = {} as any; + parameters.fileWriter = new FileWriter(outputPath); + modelManager.accept(visitor, parameters); + vscode.window.showInformationMessage(`Compiled to ${target} in '${outputPath.path}'.`); + } else { + vscode.window.showErrorMessage('Unrecognized target: ' + target); + } + } + + }catch(e) { + vscode.window.showErrorMessage("Compilation error: "+e); + } +} + export async function downloadModels(file: vscode.Uri) { try { const outputPath = Utils.dirname(file); @@ -154,7 +260,7 @@ export async function exportClassDiagram(file: vscode.Uri) { } -function getParseWebviewHtml(defaultSamplePath,defaultOutPath){ +function getDraftWebviewHtml(defaultSamplePath,defaultOutPath, defaultDataPath){ return `
@@ -163,10 +269,10 @@ function getParseWebviewHtml(defaultSamplePath,defaultOutPath){
- +
- +

@@ -193,25 +299,57 @@ function getParseWebviewHtml(defaultSamplePath,defaultOutPath){
- +


- +
` } -function getParseWebviewContent(samplePath){ +function getDraftWebviewContent(samplePath){ - const defaultOutPath = samplePath+".json"; - const html = getParseWebviewHtml(samplePath,defaultOutPath); + const defaultOutPath = samplePath+".md"; + const defaultDataPath = path.resolve(samplePath,"..","data.json") + const html = getDraftWebviewHtml(samplePath,defaultOutPath,defaultDataPath); + + const styles = getCommonStyles(); + + return ` + + + + + Accord Project + + + + ${html} + + + `; +} - const styles = `` +} + +function getParseWebviewHtml(defaultSamplePath,defaultOutPath){ + + return ` +
+
+

*Paths mentioned here are relative to the template directory

+
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+ +
+
+ +
+
` + +} + +function getParseWebviewContent(samplePath){ + + const defaultOutPath = samplePath+".json"; + const html = getParseWebviewHtml(samplePath,defaultOutPath); + + const styles = getCommonStyles(); return ` @@ -613,6 +811,8 @@ export async function getPreviewWebviewContent() { +
+
${html} `; diff --git a/package-lock.json b/package-lock.json index 4378e9c..282fc69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { + "@babel/runtime": "^7.18.9", "ietf-language-tag-regex": "^0.0.5", "slash": "^4.0.0", "vscode-uri": "^3.0.3", @@ -20,6 +21,7 @@ "@babel/core": "7.17.5", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-transform-runtime": "^7.18.10", "@babel/plugin-transform-typescript": "^7.18.8", "@babel/preset-env": "^7.18.9", "@babel/preset-typescript": "^7.18.6", @@ -1470,6 +1472,47 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz", + "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.0.tgz", + "integrity": "sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", @@ -1748,7 +1791,6 @@ "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -10371,6 +10413,37 @@ "@babel/helper-plugin-utils": "^7.18.6" } }, + "@babel/plugin-transform-runtime": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz", + "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "semver": "^6.3.0" + }, + "dependencies": { + "babel-plugin-polyfill-regenerator": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.0.tgz", + "integrity": "sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "@babel/plugin-transform-shorthand-properties": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", @@ -10579,7 +10652,6 @@ "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", - "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } diff --git a/package.json b/package.json index afcc230..d6506b9 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,9 @@ "onCommand:cicero-vscode-extension.viewClassDiagram", "onCommand:cicero-vscode-extension.triggerClause", "onCommand:cicero-vscode-extension.parseClause", - "onCommand:cicero-vscode-extension.showPreview" + "onCommand:cicero-vscode-extension.showPreview", + "onCommand:cicero-vscode-extension.compileToTarget", + "onCommand:cicero-vscode-extension.draftClause" ], "contributes": { "languages": [ @@ -132,6 +134,16 @@ "title": "Verify Signature", "category": "Accord Project" }, + { + "command": "cicero-vscode-extension.compileToTarget", + "title": "Compile Model To Target", + "category": "Accord Project" + }, + { + "command": "cicero-vscode-extension.draftClause", + "title": "Draft Clause", + "category": "Accord Project" + }, { "command": "cicero-vscode-extension.showPreview", "title": "Open Preview", @@ -178,6 +190,16 @@ "when": "resourceLangId == ciceroMark || resourceLangId == concerto", "command": "cicero-vscode-extension.showPreview", "group": "AccordProject@7" + }, + { + "when": "resourceLangId == concerto", + "command": "cicero-vscode-extension.compileToTarget", + "group": "AccordProject@8" + }, + { + "when": "resourceLangId == json", + "command": "cicero-vscode-extension.draftClause", + "group": "AccordProject@9" } ], "editor/title": [ @@ -211,6 +233,14 @@ { "command": "cicero-vscode-extension.parseClause", "when": "false" + }, + { + "command": "cicero-vscode-extension.compileToTarget", + "when": "false" + }, + { + "command": "cicero-vscode-extension.draftClause", + "when": "false" } ] } @@ -232,6 +262,7 @@ "@babel/core": "7.17.5", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-transform-runtime": "^7.18.10", "@babel/plugin-transform-typescript": "^7.18.8", "@babel/preset-env": "^7.18.9", "@babel/preset-typescript": "^7.18.6", @@ -256,6 +287,7 @@ "webpack-cli": "^4.10.0" }, "dependencies": { + "@babel/runtime": "^7.18.9", "ietf-language-tag-regex": "^0.0.5", "slash": "^4.0.0", "vscode-uri": "^3.0.3", diff --git a/webpack.config.js b/webpack.config.js index ef4f0bc..dec19da 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,7 +1,3 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ //@ts-check 'use strict'; @@ -91,78 +87,4 @@ const browerClientConfig = { }, }; -/** @type WebpackConfig */ -/** -const browerServerConfig = { - mode:"none", - target:"webworker", - entry: { - 'server': './server/src/browserServerMain.ts' - }, - output: { - filename: "[name].js", - path: path.join(__dirname,'server','out','web'), - libraryTarget: 'var', - library: 'serverExportVar' - }, - resolve: { - mainFields: ['browser','module', 'main'], - extensions: ['.ts','.js'], // support ts-files and js-files - alias: {}, - fallback: { - //'child_process':false, - 'path': require.resolve("path-browserify"), - 'http': require.resolve('stream-http'), - 'crypto': require.resolve('crypto-browserify'), - 'buffer': require.resolve('buffer/'), - 'https': require.resolve('https-browserify'), - 'url':require.resolve('url/'), - 'stream':require.resolve('stream-browserify'), - // Webpack 5 no longer polyfills Node.js core modules automatically. - // see https://webpack.js.org/configuration/resolve/#resolvefallback - // for the list of Node.js core module polyfills. - 'assert': require.resolve('assert'), - 'fs':false, - 'zlib':require.resolve('browserify-zlib'), - 'os': require.resolve('os-browserify/browser'), - 'net':false, - 'tls':false, - 'constants':false, - 'tty':false - }, - }, - module: { - rules: [ - { - test: /\.ts$/, - exclude: /node_modules/, - use: [ - { - loader: 'ts-loader', - }, - ], - }, - ], - }, - externals: { - vscode: 'commonjs vscode', // ignored because it doesn't exist - }, - performance: { - hints: false, - }, - devtool: 'source-map', - plugins: [ - new webpack.ProvidePlugin({ - Buffer: ['buffer', 'Buffer'], - }), - new webpack.ProvidePlugin({ - process: 'process/browser', // provide a shim for the global `process` variable - }), - new NodePolyfillPlugin(), - - ], - -} -*/ - module.exports = [ browerClientConfig ];