diff --git a/package-lock.json b/package-lock.json index 8678af8..d7e8b38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "jszip": "^3.6.0", "lodash-amd": "^4.17.15", "webgme-bindings": "github:webgme/bindings", - "webgme-json-importer": "^1.2.0" + "webgme-json-importer": "github:deepforge-dev/webgme-json-importer" }, "devDependencies": { "@rollup/plugin-commonjs": "^17.1.0", @@ -3463,20 +3463,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -5811,24 +5797,6 @@ "node": ">=0.10.0" } }, - "node_modules/nunjucks/node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - }, - "engines": { - "node": ">= 4.0" - } - }, "node_modules/nunjucks/node_modules/glob-parent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", @@ -9024,9 +8992,8 @@ } }, "node_modules/webgme-bindings": { - "version": "1.2.1", - "resolved": "git+ssh://git@github.com/webgme/bindings.git#95cd3b8fc4fd7bf383a6d6fcc0a15928c634915f", - "integrity": "sha512-5Q/+GNVd/md4GxdCjGYI78CvFWyBxoIeVBSgu+FZL2k3CEgMjopawqHq/qH3a6T7fdAZV2BFpuVI0zD9e48W8g==", + "version": "1.2.2", + "resolved": "git+ssh://git@github.com/webgme/bindings.git#985ea14d159f3001bc831a464c2d60d5f970333e", "license": "MIT", "dependencies": { "bindings": "^1.5.0", @@ -9114,9 +9081,8 @@ "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" }, "node_modules/webgme-json-importer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/webgme-json-importer/-/webgme-json-importer-1.2.0.tgz", - "integrity": "sha512-4BVN6OfUOZLGdmgo95LDDwS2HmgGw+3x+tnfB6oDHThAVAs7Mk7I479u5yIiVhww4DJPPe67J0sMStS0fC476Q==", + "version": "1.3.0", + "resolved": "git+ssh://git@github.com/deepforge-dev/webgme-json-importer.git#f0d33eaf7309a4be77f6c871b55913a6fdcc3305", "peerDependencies": { "webgme": "^2.23.0" } @@ -12530,13 +12496,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -14465,16 +14424,6 @@ } } }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, "glob-parent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", @@ -17074,8 +17023,7 @@ } }, "webgme-bindings": { - "version": "git+ssh://git@github.com/webgme/bindings.git#95cd3b8fc4fd7bf383a6d6fcc0a15928c634915f", - "integrity": "sha512-5Q/+GNVd/md4GxdCjGYI78CvFWyBxoIeVBSgu+FZL2k3CEgMjopawqHq/qH3a6T7fdAZV2BFpuVI0zD9e48W8g==", + "version": "git+ssh://git@github.com/webgme/bindings.git#985ea14d159f3001bc831a464c2d60d5f970333e", "from": "webgme-bindings@github:webgme/bindings", "requires": { "bindings": "^1.5.0", @@ -17155,9 +17103,8 @@ } }, "webgme-json-importer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/webgme-json-importer/-/webgme-json-importer-1.2.0.tgz", - "integrity": "sha512-4BVN6OfUOZLGdmgo95LDDwS2HmgGw+3x+tnfB6oDHThAVAs7Mk7I479u5yIiVhww4DJPPe67J0sMStS0fC476Q==", + "version": "git+ssh://git@github.com/deepforge-dev/webgme-json-importer.git#f0d33eaf7309a4be77f6c871b55913a6fdcc3305", + "from": "webgme-json-importer@github:deepforge-dev/webgme-json-importer", "requires": {} }, "webgme-ot": { diff --git a/package.json b/package.json index bba83a0..a3d780c 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "jszip": "^3.6.0", "lodash-amd": "^4.17.15", "webgme-bindings": "github:webgme/bindings", - "webgme-json-importer": "^1.2.0" + "webgme-json-importer": "github:deepforge-dev/webgme-json-importer" }, "description": "First, install the electric-circuits following: - [NodeJS](https://nodejs.org/en/) (v4.x.x recommended) - [MongoDB](https://www.mongodb.com/)", "main": "app.js", diff --git a/src/common/AnnotationWJIToCircuitTransformer.js b/src/common/AnnotationWJIToCircuitTransformer.js new file mode 100644 index 0000000..ee1a8b9 --- /dev/null +++ b/src/common/AnnotationWJIToCircuitTransformer.js @@ -0,0 +1,95 @@ +/* globals define */ +function factory(guid) { + class AnnotationWJIToCircuitTransformer { + transform(annotationsWJI) { + this._transformIntersections(annotationsWJI); + this._addPortToJunctions(annotationsWJI); + this._reassignJunctionEdges(annotationsWJI); + } + + _transformIntersections(annotations) { + // Nodes + const intersections = annotations.children.filter(this._isIntersection); + intersections.forEach(intersection => { + intersection.id ? intersection.id = intersection.id.replace('Intersection', 'Junction'): null; + intersection.pointers.base = '@meta:Junction'; + }); + + // Edges/Wires + const wires = annotations.children.filter(this._isWire); + wires.forEach(wire => { + wire.id ? wire.id = wire.id.replace('Intersection', 'Junction'): null; + wire.pointers.src = wire.pointers.src.replace('Intersection', 'Junction'); + wire.pointers.dst = wire.pointers.dst.replace('Intersection', 'Junction'); + }); + } + + _addPortToJunctions(annotations) { + const junctions = annotations.children.filter(this._isJunction); + junctions.forEach(junction => { + junction.children = this._getPortsWJI( + ['p1', 'p2', 'p3', 'p4'] + ); + }); + } + + _reassignJunctionEdges(annotations) { + const junctions = Object.fromEntries(annotations.children.filter(this._isJunction).map(j => [j.id, j])); + const wires = annotations.children.filter(this._isWire); + + const isAJunctionId = id => !!junctions[id]; + + const getRandomChild = node => { + const index = Math.floor(Math.random() * node.children.length); + return node.children[index]; + }; + + wires.forEach(wire => { + if (isAJunctionId(wire.pointers.src)) { + wire.pointers.src = `@id:${getRandomChild(junctions[wire.pointers.src]).alias}`; + } + + if (isAJunctionId(wire.pointers.dst)) { + wire.pointers.dst = `@id:${getRandomChild(junctions[wire.pointers.dst]).alias}`; + } + }); + } + + _isIntersection(node) { + return node.pointers.base === '@meta:Intersection'; + } + + _isJunction(node) { + return node.pointers.base === '@meta:Junction'; + } + + _isWire(node) { + return node.pointers.base === '@meta:Wire'; + } + + _getPortsWJI(portNames) { + return portNames.map(name => { + const id = `${guid()}`; + const attributes = {name}; + const pointers = {base: "@meta:Pin"}; + return { + alias: id, + id: `@name:${name}`, + attributes, + pointers + }; + }); + } + } + + return AnnotationWJIToCircuitTransformer; +} + + +if (typeof define !== 'undefined') { + define(['common/util/guid'], (guid) => factory(guid)); +} else { + module.exports = factory(); +} + + diff --git a/src/plugins/CreateCircuitFromAnnotations/CreateCircuitFromAnnotations.js b/src/plugins/CreateCircuitFromAnnotations/CreateCircuitFromAnnotations.js new file mode 100644 index 0000000..22a4612 --- /dev/null +++ b/src/plugins/CreateCircuitFromAnnotations/CreateCircuitFromAnnotations.js @@ -0,0 +1,46 @@ +/*globals define*/ +/*eslint-env node, browser*/ + +/** + * Generated by PluginGenerator 2.20.5 from webgme on Thu Apr 07 2022 13:59:26 GMT-0500 (Central Daylight Time). + * A plugin that inherits from the PluginBase. To see source code documentation about available + * properties and methods visit %host%/docs/source/PluginBase.html. + */ + +define([ + 'plugin/PluginConfig', + 'text!./metadata.json', + 'plugin/PluginBase', + 'electric-circuits/AnnotationWJIToCircuitTransformer', + 'webgme-json-importer/JSONImporter', +], function ( + PluginConfig, + pluginMetadata, + PluginBase, + AnnotationWJIToCircuitTransformer, + JSONImporter,) { + 'use strict'; + + pluginMetadata = JSON.parse(pluginMetadata); + + class CreateCircuitFromAnnotations extends PluginBase { + constructor(props) { + super(props); + this.pluginMetadata = pluginMetadata; + } + + async main() { + const annotationWJI = await this.blobClient.getObjectAsJSON(this.getCurrentConfig().annotations); + const circuitWJITransformer = new AnnotationWJIToCircuitTransformer(); + circuitWJITransformer.transform(annotationWJI); + const importer = new JSONImporter(this.core, this.rootNode); + await importer.import(this.activeNode, annotationWJI); + await this.save('Model updated to new state.'); + this.result.setSuccess(true); + } + } + + + + return CreateCircuitFromAnnotations; +}); diff --git a/src/plugins/CreateCircuitFromAnnotations/metadata.json b/src/plugins/CreateCircuitFromAnnotations/metadata.json new file mode 100644 index 0000000..792f169 --- /dev/null +++ b/src/plugins/CreateCircuitFromAnnotations/metadata.json @@ -0,0 +1,21 @@ +{ + "id": "CreateCircuitFromAnnotations", + "name": "CreateCircuitFromAnnotations", + "version": "0.1.0", + "description": "", + "icon": { + "class": "glyphicon glyphicon-cog", + "src": "" + }, + "disableServerSideExecution": false, + "disableBrowserSideExecution": false, + "dependencies": [], + "writeAccessRequired": false, + "configStructure": [{ + "name": "annotations", + "displayName": "Input Annotations", + "description": "The input annotation JSON file in the webgme-json-import (WJI) format", + "valueType": "asset", + "readOnly": false + }] +} \ No newline at end of file diff --git a/test/plugins/CreateCircuitFromAnnotations/CreateCircuitFromAnnotations.spec.js b/test/plugins/CreateCircuitFromAnnotations/CreateCircuitFromAnnotations.spec.js new file mode 100644 index 0000000..e9dd374 --- /dev/null +++ b/test/plugins/CreateCircuitFromAnnotations/CreateCircuitFromAnnotations.spec.js @@ -0,0 +1,82 @@ +/*eslint-env node, mocha*/ +/** + * Generated by PluginGenerator 2.20.5 from webgme on Thu Apr 07 2022 13:59:26 GMT-0500 (Central Daylight Time). + */ + +describe('CreateCircuitFromAnnotations', function () { + var testFixture = require('../../globals'), + gmeConfig = testFixture.getGmeConfig(), + expect = testFixture.expect, + logger = testFixture.logger.fork('CreateCircuitFromAnnotations'), + PluginCliManager = testFixture.WebGME.PluginCliManager, + projectName = 'testProject', + pluginName = 'CreateCircuitFromAnnotations', + project, + gmeAuth, + storage, + commitHash; + + before(function (done) { + testFixture.clearDBAndGetGMEAuth(gmeConfig, projectName) + .then(function (gmeAuth_) { + gmeAuth = gmeAuth_; + // This uses in memory storage. Use testFixture.getMongoStorage to persist test to database. + storage = testFixture.getMemoryStorage(logger, gmeConfig, gmeAuth); + return storage.openDatabase(); + }) + .then(function () { + var importParam = { + projectSeed: testFixture.path.join(testFixture.SEED_DIR, 'EmptyProject.webgmex'), + projectName: projectName, + branchName: 'master', + logger: logger, + gmeConfig: gmeConfig + }; + + return testFixture.importProject(storage, importParam); + }) + .then(function (importResult) { + project = importResult.project; + commitHash = importResult.commitHash; + return project.createBranch('test', commitHash); + }) + .nodeify(done); + }); + + after(function (done) { + storage.closeDatabase() + .then(function () { + return gmeAuth.unload(); + }) + .nodeify(done); + }); + + it('should run plugin and update the branch', function (done) { + var manager = new PluginCliManager(null, logger, gmeConfig), + pluginConfig = { + }, + context = { + project: project, + commitHash: commitHash, + branchName: 'test', + activeNode: '/1', + }; + + manager.executePlugin(pluginName, pluginConfig, context, function (err, pluginResult) { + try { + expect(err).to.equal(null); + expect(typeof pluginResult).to.equal('object'); + expect(pluginResult.success).to.equal(true); + } catch (e) { + done(e); + return; + } + + project.getBranchHash('test') + .then(function (branchHash) { + expect(branchHash).to.not.equal(commitHash); + }) + .nodeify(done); + }); + }); +}); diff --git a/webgme-setup.json b/webgme-setup.json index a0e725a..1f16bca 100644 --- a/webgme-setup.json +++ b/webgme-setup.json @@ -21,6 +21,10 @@ "ConvertNetlistToCircuit": { "src": "src/plugins/ConvertNetlistToCircuit", "test": "test/plugins/ConvertNetlistToCircuit" + }, + "CreateCircuitFromAnnotations": { + "src": "src/plugins/CreateCircuitFromAnnotations", + "test": "test/plugins/CreateCircuitFromAnnotations" } }, "seeds": { @@ -67,4 +71,4 @@ } } } -} +} \ No newline at end of file