diff --git a/package.json b/package.json index 9f7505a01..a410fb7fd 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "promise": "8.0.1", "scratch-audio": "latest", "scratch-blocks": "latest", + "scratch-parser": "latest", "scratch-render": "latest", "scratch-storage": "^0.4.0", "script-loader": "0.7.2", diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 3d3c16791..43aa0561d 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -9,6 +9,8 @@ const sb2 = require('./serialization/sb2'); const sb3 = require('./serialization/sb3'); const StringUtil = require('./util/string-util'); const formatMessage = require('format-message'); +const validate = require('scratch-parser'); + const Variable = require('./engine/variable'); const {loadCostume} = require('./import/load-costume.js'); @@ -230,26 +232,75 @@ class VirtualMachine extends EventEmitter { return; } - // Attempt to parse JSON if string is supplied - if (typeof json === 'string') json = JSON.parse(json); - // Establish version, deserialize, and load into runtime // @todo Support Scratch 1.4 // @todo This is an extremely naïve / dangerous way of determining version. // See `scratch-parser` for a more sophisticated validation // methodology that should be adapted for use here let deserializer; - if ((typeof json.meta !== 'undefined') && (typeof json.meta.semver !== 'undefined')) { + let validatedProject; + const possibleSb3 = typeof json === 'string' ? JSON.parse(json) : json; + if ((typeof possibleSb3.meta !== 'undefined') && (typeof possibleSb3.meta.semver !== 'undefined')) { deserializer = sb3; + validatedProject = possibleSb3; } else { - deserializer = sb2; + // @todo need to handle default project + validate(json, (err, project) => { + if (err) { + // @todo Making this a warning for now. Should be updated with error handling + log.warn( + `There was an error in validating the project: ${JSON.stringify(err)}`); + deserializer = sb2; + validatedProject = possibleSb3; + } else { + deserializer = sb2; + validatedProject = project; + } + // handle the error + }); } - return deserializer.deserialize(json, this.runtime) + return deserializer.deserialize(validatedProject, this.runtime) .then(({targets, extensions}) => this.installTargets(targets, extensions, true)); } + + // /** + // * Load a project from a Scratch JSON representation. + // * @param {string} json JSON string representing a project. + // * @returns {Promise} Promise that resolves after the project has loaded + // */ + // fromJSON (json) { + // // Clear the current runtime + // this.clear(); + // + // // Validate & parse + // if (typeof json !== 'string' && typeof json !== 'object') { + // log.error('Failed to parse project. Invalid type supplied to fromJSON.'); + // return; + // } + // + // // Attempt to parse JSON if string is supplied + // if (typeof json === 'string') json = JSON.parse(json); + // + // // Establish version, deserialize, and load into runtime + // // @todo Support Scratch 1.4 + // // @todo This is an extremely naïve / dangerous way of determining version. + // // See `scratch-parser` for a more sophisticated validation + // // methodology that should be adapted for use here + // let deserializer; + // if ((typeof json.meta !== 'undefined') && (typeof json.meta.semver !== 'undefined')) { + // deserializer = sb3; + // } else { + // deserializer = sb2; + // } + // + // return deserializer.deserialize(json, this.runtime) + // .then(({targets, extensions}) => + // this.installTargets(targets, extensions, true)); + // } + /** * Install `deserialize` results: zero or more targets after the extensions (if any) used by those targets. * @param {Array.} targets - the targets to be installed