diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index d59c747e..38d6e498 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -8,13 +8,13 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: actions/checkout@v4 with: persist-credentials: false - name: Install Node.js - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af + uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm - run: npm ci - run: npm run test:lint diff --git a/lib/sb3_definitions.json b/lib/sb3_definitions.json index 1c37a14a..08aca332 100644 --- a/lib/sb3_definitions.json +++ b/lib/sb3_definitions.json @@ -15,12 +15,6 @@ {"type": "null"} ] }, - "optionalJSON": { - "oneOf": [ - {"type": "object"}, - {"type": "array"} - ] - }, "boolOrOptBoolString": { "oneOf": [ {"type": "string", @@ -35,13 +29,7 @@ {"type": "number"} ] }, - "scalarVal": { - "oneOf": [ - {"$ref":"#/definitions/optionalJSON"}, - {"$ref":"#/definitions/stringOrNumber"}, - {"type": "boolean"} - ] - }, + "scalarVal": {}, "assetId": { "type": "string", "pattern": "^[a-fA-F0-9]{32}$" diff --git a/lib/unpack.js b/lib/unpack.js index 9e4d4214..02ade903 100644 --- a/lib/unpack.js +++ b/lib/unpack.js @@ -40,7 +40,10 @@ module.exports = function (input, isSprite, callback) { // If not legacy or zip, convert buffer to UTF-8 string and return if (!isZip && !isLegacy) { - return callback(null, [input.toString('utf-8'), null]); + // In browsers, the native TextDecoder can handle much larger values than the JavaScript polyfill for + // Buffer.toString('utf-8'), particularly in Chrome. + const decoder = new TextDecoder(); + return callback(null, [decoder.decode(input), null]); } // Return error if legacy encoding detected diff --git a/lib/validate.js b/lib/validate.js index 0b65d937..95322147 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -44,7 +44,9 @@ module.exports = function (isSprite, input, callback) { // eslint-disable-next-line global-require var sb3fix = require('@turbowarp/sb3fix'); - var fixed = sb3fix.fixJSON(input); + var fixed = sb3fix.fixJSON(input, { + platform: 'turbowarp' + }); validate(isSprite, fixed, function (err2, result2) { if (err2) { // Original validation error will be most useful diff --git a/package-lock.json b/package-lock.json index 58938676..f058dd9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@turbowarp/json": "^0.1.1", "@turbowarp/jszip": "^3.11.0", - "@turbowarp/sb3fix": "^0.3.0", + "@turbowarp/sb3fix": "^0.4.0", "ajv": "6.3.0", "pify": "4.0.1" }, @@ -2482,9 +2482,9 @@ "integrity": "sha512-9nWywp+0SH7ROVzQPQQO9gMWBikahsqyMWp1Ku8VV0q+q6bnx6dS0aNPTjqTtF2GHAY55hcREsqKzaoUdWBSwg==" }, "node_modules/@turbowarp/jszip": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@turbowarp/jszip/-/jszip-3.11.0.tgz", - "integrity": "sha512-G+xld2rPv0b7ZKIk4ZZLW8l46+VfdUsreYjWml8bl3IHrmQXgijkmiDwTq17CBf5GPlz4+F/TpJdclq0jhMSVQ==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@turbowarp/jszip/-/jszip-3.12.0.tgz", + "integrity": "sha512-nTKFFc1rUToxTdxUKPIou3YKUsSelgEoyx4TAPzK/0BkGPntkenp9zoJOSnxnGWNchVXYVZv01+3aZwlS1K8hw==", "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", @@ -2494,12 +2494,12 @@ } }, "node_modules/@turbowarp/sb3fix": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@turbowarp/sb3fix/-/sb3fix-0.3.0.tgz", - "integrity": "sha512-tZjpPb37UUnr6mxeZ12FLqHFhQ66rIUEIfFMWoLLzmt8VFE6JjM74chyphsB3AwON5ehs678zzXkhRSOZgPK3A==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@turbowarp/sb3fix/-/sb3fix-0.4.0.tgz", + "integrity": "sha512-DC1u1B2nugkANEzQyioPFEYPYtZvr8NFvZkpYlxkoBOsn+LPJP1F486vNzvkGu2MAGTfWR0QmsBTRdanrppCrg==", "license": "MPL-2.0", "dependencies": { - "@turbowarp/jszip": "^3.11.0" + "@turbowarp/jszip": "^3.12.0" } }, "node_modules/@types/glob": { @@ -20281,9 +20281,9 @@ "integrity": "sha512-9nWywp+0SH7ROVzQPQQO9gMWBikahsqyMWp1Ku8VV0q+q6bnx6dS0aNPTjqTtF2GHAY55hcREsqKzaoUdWBSwg==" }, "@turbowarp/jszip": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@turbowarp/jszip/-/jszip-3.11.0.tgz", - "integrity": "sha512-G+xld2rPv0b7ZKIk4ZZLW8l46+VfdUsreYjWml8bl3IHrmQXgijkmiDwTq17CBf5GPlz4+F/TpJdclq0jhMSVQ==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@turbowarp/jszip/-/jszip-3.12.0.tgz", + "integrity": "sha512-nTKFFc1rUToxTdxUKPIou3YKUsSelgEoyx4TAPzK/0BkGPntkenp9zoJOSnxnGWNchVXYVZv01+3aZwlS1K8hw==", "requires": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -20292,11 +20292,11 @@ } }, "@turbowarp/sb3fix": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@turbowarp/sb3fix/-/sb3fix-0.3.0.tgz", - "integrity": "sha512-tZjpPb37UUnr6mxeZ12FLqHFhQ66rIUEIfFMWoLLzmt8VFE6JjM74chyphsB3AwON5ehs678zzXkhRSOZgPK3A==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@turbowarp/sb3fix/-/sb3fix-0.4.0.tgz", + "integrity": "sha512-DC1u1B2nugkANEzQyioPFEYPYtZvr8NFvZkpYlxkoBOsn+LPJP1F486vNzvkGu2MAGTfWR0QmsBTRdanrppCrg==", "requires": { - "@turbowarp/jszip": "^3.11.0" + "@turbowarp/jszip": "^3.12.0" } }, "@types/glob": { diff --git a/package.json b/package.json index 1a3a39fb..f8e890ed 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "dependencies": { "@turbowarp/json": "^0.1.1", "@turbowarp/jszip": "^3.11.0", - "@turbowarp/sb3fix": "^0.3.0", + "@turbowarp/sb3fix": "^0.4.0", "ajv": "6.3.0", "pify": "4.0.1" }, diff --git a/test/fixtures/tw_non_scalar_variables.json b/test/fixtures/tw_non_scalar_variables.json new file mode 100644 index 00000000..89a4e242 --- /dev/null +++ b/test/fixtures/tw_non_scalar_variables.json @@ -0,0 +1,95 @@ +{ + "targets": [ + { + "isStage": true, + "name": "Stage", + "variables": { + "8Ct!xBe$u3!.nz_Bh/]#": [ + "object", + { + "hello": "world" + } + ] + }, + "lists": { + "u(}PhnFj*Oe*`Ka~{hhc": [ + "list of objects", + [ + { + "a": 1 + }, + { + "b": 2 + } + ] + ] + }, + "broadcasts": {}, + "blocks": {}, + "comments": {}, + "currentCostume": 0, + "costumes": [ + { + "name": "backdrop1", + "dataFormat": "svg", + "assetId": "cd21514d0531fdffb22204e0ec5ed84a", + "md5ext": "cd21514d0531fdffb22204e0ec5ed84a.svg", + "rotationCenterX": 240, + "rotationCenterY": 180 + } + ], + "sounds": [], + "volume": 100, + "layerOrder": 0, + "tempo": 60, + "videoTransparency": 50, + "videoState": "on", + "textToSpeechLanguage": null + } + ], + "monitors": [ + { + "id": "8Ct!xBe$u3!.nz_Bh/]#", + "mode": "default", + "opcode": "data_variable", + "params": { + "VARIABLE": "object" + }, + "spriteName": null, + "value": 0, + "width": 0, + "height": 0, + "x": 5, + "y": 5, + "visible": true, + "sliderMin": 0, + "sliderMax": 100, + "isDiscrete": true + }, + { + "id": "u(}PhnFj*Oe*`Ka~{hhc", + "mode": "list", + "opcode": "data_listcontents", + "params": { + "LIST": "list of objects" + }, + "spriteName": null, + "value": [], + "width": 0, + "height": 0, + "x": 5, + "y": 32, + "visible": true + } + ], + "extensions": [], + "meta": { + "semver": "3.0.0", + "vm": "0.2.0", + "agent": "", + "platform": { + "name": "TurboWarp", + "url": "https://turbowarp.org/" + } + } +} \ No newline at end of file diff --git a/test/integration/tw_non_scalar_variables.js b/test/integration/tw_non_scalar_variables.js new file mode 100644 index 00000000..333a1abd --- /dev/null +++ b/test/integration/tw_non_scalar_variables.js @@ -0,0 +1,23 @@ +const test = require('tap').test; +const fs = require('fs'); +const path = require('path'); +const parser = require('../../index'); + +test('non scalar variables', function (t) { + const fixture = fs.readFileSync(path.join(__dirname, '../fixtures/tw_non_scalar_variables.json'), 'utf-8'); + parser(fixture, false, function (err, result) { + t.equal(err, null); + t.same(result[0].targets[0].variables['8Ct!xBe$u3!.nz_Bh/]#'][1], { + hello: 'world' + }); + t.same(result[0].targets[0].lists['u(}PhnFj*Oe*`Ka~{hhc'][1], [ + { + a: 1 + }, + { + b: 2 + } + ]); + t.end(); + }); +});