diff --git a/src/playground/index.html b/src/playground/index.html index 2d2f1698c..d248b9847 100644 --- a/src/playground/index.html +++ b/src/playground/index.html @@ -73,7 +73,7 @@ diff --git a/src/serialization/sb2.js b/src/serialization/sb2.js index 53a7cfc4d..4278656f2 100644 --- a/src/serialization/sb2.js +++ b/src/serialization/sb2.js @@ -15,8 +15,8 @@ const specMap = require('./sb2_specmap'); const Variable = require('../engine/variable'); const List = require('../engine/list'); -const loadCostume = require('./load-costume.js'); -const loadSound = require('./load-sound.js'); +const loadCostume = require('../import/load-costume.js'); +const loadSound = require('../import/load-sound.js'); /** * Convert a Scratch 2.0 procedure string (e.g., "my_procedure %s %b %n") diff --git a/src/serialization/sb3.js b/src/serialization/sb3.js index 7543b4cd1..4eb06dd5e 100644 --- a/src/serialization/sb3.js +++ b/src/serialization/sb3.js @@ -4,27 +4,26 @@ * JSON and then generates all needed scratch-vm runtime structures. */ -var package = require('../../package.json'); -var Blocks = require('../engine/blocks'); -var RenderedTarget = require('../sprites/rendered-target'); -var Sprite = require('../sprites/sprite'); -var Variable = require('../engine/variable'); -var List = require('../engine/list'); +const vmPackage = require('../../package.json'); +const Blocks = require('../engine/blocks'); +const Sprite = require('../sprites/sprite'); +const Variable = require('../engine/variable'); +const List = require('../engine/list'); /** * Serializes the specified VM runtime. * @param {!Runtime} runtime VM runtime instance to be serialized. * @return {string} Serialized runtime instance. */ -var serialize = function (runtime) { +const serialize = function (runtime) { // Fetch targets - var obj = Object.create(null); + const obj = Object.create(null); obj.targets = runtime.targets; // Assemble metadata - var meta = Object.create(null); + const meta = Object.create(null); meta.semver = '3.0.0'; - meta.vm = package.version; + meta.vm = vmPackage.version; // Attach full user agent string to metadata if available meta.agent = null; @@ -37,36 +36,36 @@ var serialize = function (runtime) { /** * Parse a single "Scratch object" and create all its in-memory VM objects. - * @param {!Object} object From-JSON "Scratch object:" sprite, stage, watcher. + * @param {!object} object From-JSON "Scratch object:" sprite, stage, watcher. * @param {!Runtime} runtime Runtime object to load all structures into. * @return {?Target} Target created (stage or sprite). */ -var parseScratchObject = function (object, runtime) { +const parseScratchObject = function (object, runtime) { if (!object.hasOwnProperty('name')) { // Watcher/monitor - skip this object until those are implemented in VM. // @todo return; } // Blocks container for this object. - var blocks = new Blocks(); + const blocks = new Blocks(); // @todo: For now, load all Scratch objects (stage/sprites) as a Sprite. - var sprite = new Sprite(blocks, runtime); + const sprite = new Sprite(blocks, runtime); // Sprite/stage name from JSON. if (object.hasOwnProperty('name')) { sprite.name = object.name; } if (object.hasOwnProperty('blocks')) { - for (blockId in object.blocks) { + for (let blockId in object.blocks) { blocks.createBlock(object.blocks[blockId]); } - console.log(blocks); + // console.log(blocks); } // Costumes from JSON. if (object.hasOwnProperty('costumes') || object.hasOwnProperty('costume')) { - for (var i = 0; i < object.costumeCount; i++) { - var costume = object.costumes[i]; + for (let i = 0; i < object.costumeCount; i++) { + const costume = object.costumes[i]; // @todo: Make sure all the relevant metadata is being pulled out. sprite.costumes.push({ skin: costume.skin, @@ -79,8 +78,8 @@ var parseScratchObject = function (object, runtime) { } // Sounds from JSON if (object.hasOwnProperty('sounds')) { - for (var s = 0; s < object.sounds.length; s++) { - var sound = object.sounds[s]; + for (let s = 0; s < object.sounds.length; s++) { + const sound = object.sounds[s]; sprite.sounds.push({ format: sound.format, fileUrl: sound.fileUrl, @@ -93,13 +92,13 @@ var parseScratchObject = function (object, runtime) { } } // Create the first clone, and load its run-state from JSON. - var target = sprite.createClone(); + const target = sprite.createClone(); // Add it to the runtime's list of targets. runtime.targets.push(target); // Load target properties from JSON. if (object.hasOwnProperty('variables')) { - for (var j = 0; j < object.variables.length; j++) { - var variable = object.variables[j]; + for (let j = 0; j < object.variables.length; j++) { + const variable = object.variables[j]; target.variables[variable.name] = new Variable( variable.name, variable.value, @@ -108,8 +107,8 @@ var parseScratchObject = function (object, runtime) { } } if (object.hasOwnProperty('lists')) { - for (var k = 0; k < object.lists.length; k++) { - var list = object.lists[k]; + for (let k = 0; k < object.lists.length; k++) { + const list = object.lists[k]; // @todo: monitor properties. target.lists[list.listName] = new List( list.listName, @@ -143,8 +142,8 @@ var parseScratchObject = function (object, runtime) { } target.updateAllDrawableProperties(); - console.log("returning target:"); - console.log(target); + // console.log('returning target:'); + // console.log(target); return target; }; @@ -154,8 +153,8 @@ var parseScratchObject = function (object, runtime) { * @param {string} json Stringified JSON representation of a VM runtime. * @param {Runtime} runtime Runtime instance */ -var deserialize = function (json, runtime) { - for (var i = 0; i < json.targets.length; i++) { +const deserialize = function (json, runtime) { + for (let i = 0; i < json.targets.length; i++) { parseScratchObject(json.targets[i], runtime); } }; diff --git a/src/virtual-machine.js b/src/virtual-machine.js index a69539a06..745d9089a 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -145,22 +145,7 @@ class VirtualMachine extends EventEmitter { */ loadProject (json) { // @todo: Handle other formats, e.g., Scratch 1.4, Scratch 3.0. - return this.fromJSON(json, this.runtime).then(targets => { - this.clear(); - for (let n = 0; n < targets.length; n++) { - if (targets[n] !== null) { - this.runtime.targets.push(targets[n]); - targets[n].updateAllDrawableProperties(); - } - } - // Select the first target for editing, e.g., the first sprite. - this.editingTarget = this.runtime.targets[1]; - - // Update the VM user's knowledge of targets and blocks on the workspace. - this.emitTargetsUpdate(); - this.emitWorkspaceUpdate(); - this.runtime.setEditingTarget(this.editingTarget); - }); + return this.fromJSON(json); } /** @@ -181,7 +166,7 @@ class VirtualMachine extends EventEmitter { } /** - * return a project in a Scratch 3.0 JSON representation. + * @returns {string} Project in a Scratch 3.0 JSON representation. */ saveProjectSb3 () { // @todo: Handle other formats, e.g., Scratch 1.4, Scratch 2.0. @@ -199,6 +184,7 @@ class VirtualMachine extends EventEmitter { /** * 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 @@ -214,38 +200,46 @@ class VirtualMachine extends EventEmitter { // @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 - if ((typeof json.meta !== 'undefined') && (typeof json.meta.semver !== 'undefined') ) { - sb3.deserialize(json, this.runtime); + let deserializer; + if ((typeof json.meta !== 'undefined') && (typeof json.meta.semver !== 'undefined')) { + deserializer = sb3; } else { - sb2.deserialize(json, this.runtime); + deserializer = sb2; } - // Select the first target for editing, e.g., the first sprite. - this.editingTarget = this.runtime.targets[1]; + return deserializer.deserialize(json, this.runtime).then(targets => { + this.clear(); + for (let n = 0; n < targets.length; n++) { + if (targets[n] !== null) { + this.runtime.targets.push(targets[n]); + targets[n].updateAllDrawableProperties(); + } + } + // Select the first target for editing, e.g., the first sprite. + this.editingTarget = this.runtime.targets[1]; - // Update the VM user's knowledge of targets and blocks on the workspace. - this.emitTargetsUpdate(); - this.emitWorkspaceUpdate(); - this.runtime.setEditingTarget(this.editingTarget); + // Update the VM user's knowledge of targets and blocks on the workspace. + this.emitTargetsUpdate(); + this.emitWorkspaceUpdate(); + this.runtime.setEditingTarget(this.editingTarget); + }); } /** * Add a single sprite from the "Sprite2" (i.e., SB2 sprite) format. * @param {string} json JSON string representing the sprite. + * @returns {Promise} Promise that resolves after the sprite is added */ addSprite2 (json) { // Select new sprite. - this.editingTarget = sb2.deserialize(json, this.runtime, true); - /* @todo Promisify this - .then(targets => { - this.runtime.targets.push(targets[0]); - this.editingTarget = targets[0]; - }) - */ - // Update the VM user's knowledge of targets and blocks on the workspace. - this.emitTargetsUpdate(); - this.emitWorkspaceUpdate(); - this.runtime.setEditingTarget(this.editingTarget); + return sb2.deserialize(json, this.runtime, true).then(targets => { + this.runtime.targets.push(targets[0]); + this.editingTarget = targets[0]; + // Update the VM user's knowledge of targets and blocks on the workspace. + this.emitTargetsUpdate(); + this.emitWorkspaceUpdate(); + this.runtime.setEditingTarget(this.editingTarget); + }); } /** diff --git a/test/integration/import_sb2.js b/test/integration/import_sb2.js index 547b645ea..2602783fd 100644 --- a/test/integration/import_sb2.js +++ b/test/integration/import_sb2.js @@ -5,7 +5,7 @@ const extract = require('../fixtures/extract'); const renderedTarget = require('../../src/sprites/rendered-target'); const runtime = require('../../src/engine/runtime'); -const sb2 = require('../../src/import/sb2import'); +const sb2 = require('../../src/serialization/sb2'); test('spec', t => { t.type(sb2, 'function'); diff --git a/test/unit/serialization_sb2.js b/test/unit/serialization_sb2.js index 530311d33..7a0bec03f 100644 --- a/test/unit/serialization_sb2.js +++ b/test/unit/serialization_sb2.js @@ -1,51 +1,53 @@ -var path = require('path'); -var test = require('tap').test; -var extract = require('../fixtures/extract'); +const path = require('path'); +const test = require('tap').test; +const extract = require('../fixtures/extract'); -var renderedTarget = require('../../src/sprites/rendered-target'); -var runtime = require('../../src/engine/runtime'); -var sb2 = require('../../src/serialization/sb2'); +const RenderedTarget = require('../../src/sprites/rendered-target'); +const Runtime = require('../../src/engine/runtime'); +const sb2 = require('../../src/serialization/sb2'); -test('spec', function (t) { +test('spec', t => { t.type(sb2, 'object'); t.type(sb2.deserialize, 'function'); t.end(); }); -test('default', function (t) { +test('default', t => { // Get SB2 JSON (string) - var uri = path.resolve(__dirname, '../fixtures/default.sb2'); - var file = extract(uri); + const uri = path.resolve(__dirname, '../fixtures/default.sb2'); + const file = extract(uri); // Create runtime instance & load SB2 into it - var rt = new runtime(); - sb2.deserialize(file, rt); + const rt = new Runtime(); + sb2.deserialize(file, rt).then(targets => { + console.dir(targets); - // Test - t.type(file, 'string'); - t.type(rt, 'object'); - t.type(rt.targets, 'object'); + // Test + t.type(file, 'string'); + t.type(rt, 'object'); + t.type(targets, 'object'); - t.ok(rt.targets[0] instanceof renderedTarget); - t.type(rt.targets[0].id, 'string'); - t.type(rt.targets[0].blocks, 'object'); - t.type(rt.targets[0].variables, 'object'); - t.type(rt.targets[0].lists, 'object'); + t.ok(targets[0] instanceof RenderedTarget); + t.type(targets[0].id, 'string'); + t.type(targets[0].blocks, 'object'); + t.type(targets[0].variables, 'object'); + t.type(targets[0].lists, 'object'); - t.equal(rt.targets[0].isOriginal, true); - t.equal(rt.targets[0].currentCostume, 0); - t.equal(rt.targets[0].isOriginal, true); - t.equal(rt.targets[0].isStage, true); + t.equal(targets[0].isOriginal, true); + t.equal(targets[0].currentCostume, 0); + t.equal(targets[0].isOriginal, true); + t.equal(targets[0].isStage, true); - t.ok(rt.targets[1] instanceof renderedTarget); - t.type(rt.targets[1].id, 'string'); - t.type(rt.targets[1].blocks, 'object'); - t.type(rt.targets[1].variables, 'object'); - t.type(rt.targets[1].lists, 'object'); + t.ok(targets[1] instanceof RenderedTarget); + t.type(targets[1].id, 'string'); + t.type(targets[1].blocks, 'object'); + t.type(targets[1].variables, 'object'); + t.type(targets[1].lists, 'object'); - t.equal(rt.targets[1].isOriginal, true); - t.equal(rt.targets[1].currentCostume, 0); - t.equal(rt.targets[1].isOriginal, true); - t.equal(rt.targets[1].isStage, false); - t.end(); + t.equal(targets[1].isOriginal, true); + t.equal(targets[1].currentCostume, 0); + t.equal(targets[1].isOriginal, true); + t.equal(targets[1].isStage, false); + t.end(); + }); }); diff --git a/test/unit/serialization_sb3.js b/test/unit/serialization_sb3.js index 0ec56284d..761b0b54c 100644 --- a/test/unit/serialization_sb3.js +++ b/test/unit/serialization_sb3.js @@ -1,19 +1,19 @@ -var test = require('tap').test; -var VirtualMachine = require('../../src/index'); -var sb3 = require('../../src/serialization/sb3'); +const test = require('tap').test; +const VirtualMachine = require('../../src/index'); +const sb3 = require('../../src/serialization/sb3'); -test('serialize', function (t) { - var vm = new VirtualMachine(); +test('serialize', t => { + const vm = new VirtualMachine(); vm.fromJSON(JSON.stringify(require('../fixtures/demo.json'))); - var result = sb3.serialize(vm.runtime); + const result = sb3.serialize(vm.runtime); console.dir(JSON.stringify(result)); - // @todo Analyize + // @todo Analyze t.end(); }); -test('deserialize', function (t) { - var vm = new VirtualMachine(); - var result = sb3.deserialize('', vm.runtime); +test('deserialize', t => { + const vm = new VirtualMachine(); + const result = sb3.deserialize('', vm.runtime); // @todo Analyize t.end(); });