diff --git a/src/virtual-machine.js b/src/virtual-machine.js index dea8d65fd1..dde2e3f662 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -497,8 +497,6 @@ class VirtualMachine extends EventEmitter { * @returns {JSZip} JSZip zip object representing the sb3. */ _saveProjectZip () { - const soundDescs = serializeSounds(this.runtime); - const costumeDescs = serializeCostumes(this.runtime); const projectJson = this.toJSON(); // TODO want to eventually move zip creation out of here, and perhaps @@ -507,7 +505,7 @@ class VirtualMachine extends EventEmitter { // Put everything in a zip file zip.file('project.json', projectJson); - this._addFileDescsToZip(costumeDescs.concat(soundDescs), zip); + this._addFileDescsToZip(this.serializeAssets(), zip); return zip; } @@ -544,14 +542,12 @@ class VirtualMachine extends EventEmitter { * @returns {Record} Map of file name to the raw data for that file. */ saveProjectSb3DontZip () { - const soundDescs = serializeSounds(this.runtime); - const costumeDescs = serializeCostumes(this.runtime); const projectJson = this.toJSON(); const files = { 'project.json': new _TextEncoder().encode(projectJson) }; - for (const fileDesc of costumeDescs.concat(soundDescs)) { + for (const fileDesc of this.serializeAssets()) { files[fileDesc.fileName] = fileDesc.fileContent; } @@ -569,6 +565,16 @@ class VirtualMachine extends EventEmitter { ), []); } + /** + * @param {string} targetId Optional ID of target to export + * @returns {Array<{fileName: string; fileContent: Uint8Array;}} list of file descs + */ + serializeAssets (targetId) { + const costumeDescs = serializeCostumes(this.runtime, targetId); + const soundDescs = serializeSounds(this.runtime, targetId); + return costumeDescs.concat(soundDescs); + } + _addFileDescsToZip (fileDescs, zip) { // TODO: sort files, smallest first for (let i = 0; i < fileDescs.length; i++) { @@ -590,13 +596,11 @@ class VirtualMachine extends EventEmitter { * specified by optZipType or blob by default. */ exportSprite (targetId, optZipType) { - const soundDescs = serializeSounds(this.runtime, targetId); - const costumeDescs = serializeCostumes(this.runtime, targetId); const spriteJson = this.toJSON(targetId); const zip = new JSZip(); zip.file('sprite.json', spriteJson); - this._addFileDescsToZip(costumeDescs.concat(soundDescs), zip); + this._addFileDescsToZip(this.serializeAssets(targetId), zip); return zip.generateAsync({ type: typeof optZipType === 'string' ? optZipType : 'blob', diff --git a/test/integration/tw_serialize_asset_order.js b/test/integration/tw_serialize_asset_order.js index f8d9a3bb06..0ecbe1e22b 100644 --- a/test/integration/tw_serialize_asset_order.js +++ b/test/integration/tw_serialize_asset_order.js @@ -7,6 +7,25 @@ const makeTestStorage = require('../fixtures/make-test-storage'); const fixture = fs.readFileSync(path.join(__dirname, '..', 'fixtures', 'tw-serialize-asset-order.sb3')); +test('serializeAssets serialization order', t => { + t.plan(15); + const vm = new VM(); + vm.attachStorage(makeTestStorage()); + vm.loadProject(fixture).then(() => { + const assets = vm.serializeAssets(); + for (let i = 0; i < assets.length; i++) { + // won't deduplicate assets, so expecting 8 costumes, 7 sounds + // 8 costumes, 6 sounds + if (i < 8) { + t.ok(assets[i].fileName.endsWith('.svg'), `file ${i + 1} is costume`); + } else { + t.ok(assets[i].fileName.endsWith('.wav'), `file ${i + 1} is sound`); + } + } + t.end(); + }); +}); + test('saveProjectSb3 serialization order', t => { t.plan(13); const vm = new VM();