From 79169c81b325982a8f03588affde915ce7d0c918 Mon Sep 17 00:00:00 2001 From: Karishma Chadha Date: Mon, 26 Feb 2018 22:43:55 -0500 Subject: [PATCH 1/4] Use scratch-parser to validate structure of project json files. --- package.json | 1 + src/virtual-machine.js | 63 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 6 deletions(-) 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 From 59d1c2a0b37157e5ce22c0ea6ea94e1fb0a96fff Mon Sep 17 00:00:00 2001 From: Karishma Chadha Date: Wed, 28 Feb 2018 10:02:02 -0500 Subject: [PATCH 2/4] Code cleanup and actually throw errors when project fails to load. Depends on scratch-gui loading sb3 version of default project. --- src/virtual-machine.js | 53 +++++++----------------------------------- 1 file changed, 8 insertions(+), 45 deletions(-) diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 43aa0561d..4734623c6 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -228,8 +228,9 @@ class VirtualMachine extends EventEmitter { // Validate & parse if (typeof json !== 'string' && typeof json !== 'object') { - log.error('Failed to parse project. Invalid type supplied to fromJSON.'); - return; + const invalidTypeError = 'Failed to parse project. Invalid type supplied to fromJSON.'; + log.error(invalidTypeError); + throw new Error(invalidTypeError); } // Establish version, deserialize, and load into runtime @@ -244,19 +245,17 @@ class VirtualMachine extends EventEmitter { deserializer = sb3; validatedProject = possibleSb3; } else { - // @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; + const errorMessage = + `The given project could not be validated, parsing failed with error: ${JSON.stringify(err)}`; + log.error(errorMessage); + throw new Error(errorMessage); + } else { deserializer = sb2; validatedProject = project; } - // handle the error }); } @@ -265,42 +264,6 @@ class VirtualMachine extends EventEmitter { 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 From 7c7b01664315f8f3336a6296d4db363f6ecbaa83 Mon Sep 17 00:00:00 2001 From: Karishma Chadha Date: Wed, 28 Feb 2018 11:52:22 -0500 Subject: [PATCH 3/4] scratch-parser expects json string... --- src/virtual-machine.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 4734623c6..2dbfe5d46 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -245,7 +245,9 @@ class VirtualMachine extends EventEmitter { deserializer = sb3; validatedProject = possibleSb3; } else { - validate(json, (err, project) => { + // scratch-parser expects a json string or a buffer + const possibleSb2 = typeof json === 'object' ? JSON.stringify(json) : json; + validate(possibleSb2, (err, project) => { if (err) { const errorMessage = `The given project could not be validated, parsing failed with error: ${JSON.stringify(err)}`; From d9fb315e3b46c8561f1fad08654b32cad6a41b7f Mon Sep 17 00:00:00 2001 From: Karishma Chadha Date: Wed, 28 Feb 2018 17:10:54 -0500 Subject: [PATCH 4/4] Removing log messages. --- src/virtual-machine.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 2dbfe5d46..c7484a4e2 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -228,9 +228,7 @@ class VirtualMachine extends EventEmitter { // Validate & parse if (typeof json !== 'string' && typeof json !== 'object') { - const invalidTypeError = 'Failed to parse project. Invalid type supplied to fromJSON.'; - log.error(invalidTypeError); - throw new Error(invalidTypeError); + throw new Error('Failed to parse project. Invalid type supplied to fromJSON.'); } // Establish version, deserialize, and load into runtime @@ -249,10 +247,8 @@ class VirtualMachine extends EventEmitter { const possibleSb2 = typeof json === 'object' ? JSON.stringify(json) : json; validate(possibleSb2, (err, project) => { if (err) { - const errorMessage = - `The given project could not be validated, parsing failed with error: ${JSON.stringify(err)}`; - log.error(errorMessage); - throw new Error(errorMessage); + throw new Error( + `The given project could not be validated, parsing failed with error: ${JSON.stringify(err)}`); } else { deserializer = sb2;