mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2024-12-23 06:23:37 -05:00
Serialize Infinity and NaN to 0
This commit is contained in:
parent
122443a75f
commit
7e96ef2985
5 changed files with 64 additions and 4 deletions
|
@ -14,6 +14,7 @@ const StageLayering = require('../engine/stage-layering');
|
|||
const log = require('../util/log');
|
||||
const uid = require('../util/uid');
|
||||
const MathUtil = require('../util/math-util');
|
||||
const StringUtil = require('../util/string-util');
|
||||
|
||||
const {loadCostume} = require('../import/load-costume.js');
|
||||
const {loadSound} = require('../import/load-sound.js');
|
||||
|
@ -522,7 +523,7 @@ const serialize = function (runtime, targetId) {
|
|||
|
||||
const layerOrdering = getSimplifiedLayerOrdering(originalTargetsToSerialize);
|
||||
|
||||
const flattenedOriginalTargets = JSON.parse(JSON.stringify(originalTargetsToSerialize));
|
||||
const flattenedOriginalTargets = JSON.parse(StringUtil.stringify(originalTargetsToSerialize));
|
||||
|
||||
// If the renderer is attached, and we're serializing a whole project (not a sprite)
|
||||
// add a temporary layerOrder property to each target.
|
||||
|
|
|
@ -34,7 +34,28 @@ class StringUtil {
|
|||
return [text.substring(0, index), text.substring(index + 1)];
|
||||
}
|
||||
return [text, null];
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A customized version of JSON.stringify that sets Infinity/NaN to 0,
|
||||
* instead of the default (null).
|
||||
* Needed because null is not of type number, but Infinity/NaN are, which
|
||||
* can lead to serialization producing JSON that isn't valid based on the parser schema.
|
||||
* It is also consistent with the behavior of saving 2.0 projects.
|
||||
* This is only needed when stringifying an object for saving.
|
||||
*
|
||||
* @param {!object} obj - The object to serialize
|
||||
* @return {!string} The JSON.stringified string with Infinity/NaN replaced with 0
|
||||
*/
|
||||
static stringify (obj) {
|
||||
return JSON.stringify(obj, (_key, value) => {
|
||||
if (typeof value === 'number' &&
|
||||
(value === Infinity || value === -Infinity || isNaN(value))){
|
||||
return 0;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -381,7 +381,7 @@ class VirtualMachine extends EventEmitter {
|
|||
exportSprite (targetId, optZipType) {
|
||||
const soundDescs = serializeSounds(this.runtime, targetId);
|
||||
const costumeDescs = serializeCostumes(this.runtime, targetId);
|
||||
const spriteJson = JSON.stringify(sb3.serialize(this.runtime, targetId));
|
||||
const spriteJson = StringUtil.stringify(sb3.serialize(this.runtime, targetId));
|
||||
|
||||
const zip = new JSZip();
|
||||
zip.file('sprite.json', spriteJson);
|
||||
|
@ -401,7 +401,7 @@ class VirtualMachine extends EventEmitter {
|
|||
* @return {string} Serialized state of the runtime.
|
||||
*/
|
||||
toJSON () {
|
||||
return JSON.stringify(sb3.serialize(this.runtime));
|
||||
return StringUtil.stringify(sb3.serialize(this.runtime));
|
||||
}
|
||||
|
||||
// TODO do we still need this function? Keeping it here so as not to introduce
|
||||
|
|
|
@ -63,3 +63,14 @@ test('unusedName', t => {
|
|||
);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('stringify', t => {
|
||||
const obj = {a: Infinity, b: NaN, c: -Infinity, d: 23, e: 'str'};
|
||||
const parsed = JSON.parse(StringUtil.stringify(obj));
|
||||
t.equal(parsed.a, 0);
|
||||
t.equal(parsed.b, 0);
|
||||
t.equal(parsed.c, 0);
|
||||
t.equal(parsed.d, 23);
|
||||
t.equal(parsed.e, 'str');
|
||||
t.end();
|
||||
});
|
||||
|
|
|
@ -982,3 +982,30 @@ test('Starting the VM emits an event', t => {
|
|||
t.equal(started, true);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('toJSON encodes Infinity/NaN as 0, not null', t => {
|
||||
const vm = new VirtualMachine();
|
||||
const runtime = vm.runtime;
|
||||
const spr1 = new Sprite(null, runtime);
|
||||
const stage = spr1.createClone();
|
||||
stage.isStage = true;
|
||||
stage.volume = Infinity;
|
||||
stage.tempo = NaN;
|
||||
stage.createVariable('id1', 'name1', '');
|
||||
stage.variables.id1.value = Infinity;
|
||||
stage.createVariable('id2', 'name2', '');
|
||||
stage.variables.id1.value = -Infinity;
|
||||
stage.createVariable('id3', 'name3', '');
|
||||
stage.variables.id1.value = NaN;
|
||||
|
||||
runtime.targets = [stage];
|
||||
|
||||
const json = JSON.parse(vm.toJSON());
|
||||
t.equal(json.targets[0].volume, 0);
|
||||
t.equal(json.targets[0].tempo, 0);
|
||||
t.equal(json.targets[0].variables.id1[1], 0);
|
||||
t.equal(json.targets[0].variables.id2[1], 0);
|
||||
t.equal(json.targets[0].variables.id3[1], 0);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue