@turbowarp/sb3fix 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +4 -4
  2. package/package.json +4 -3
  3. package/src/sb3fix.js +32 -17
package/README.md CHANGED
@@ -40,9 +40,9 @@ const run = async () => {
40
40
 
41
41
  // Both sb3fix methods take in an optional options object.
42
42
  const options = {
43
- // When sb3fix runs, it'll log what it's doing and what it's found. You can monitor those
43
+ // While sb3fix runs, it'll log what it's doing and what it fixed. You can monitor those
44
44
  // using this callback. These messages are primarily a debugging tool, so the exact output
45
- // is not considered part of the API. It may change without warning.
45
+ // is not stable and may change without warning.
46
46
  logCallback: (message) => {
47
47
  console.log(message);
48
48
  }
@@ -68,10 +68,10 @@ npm ci
68
68
  Source code is in the src folder. During development do:
69
69
 
70
70
  ```bash
71
- npm run watch
71
+ npm start
72
72
  ```
73
73
 
74
- Then open dist/index.html in your favorite browser.
74
+ Then open dist/index.html in your favorite browser (there isn't a localhost development server).
75
75
 
76
76
  For the final build:
77
77
 
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@turbowarp/sb3fix",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Fix corrupted Scratch projects",
5
5
  "main": "src/sb3fix.js",
6
6
  "scripts": {
7
7
  "build": "webpack -c webpack.config.js",
8
8
  "watch": "webpack --watch -c webpack.config.js",
9
+ "start": "webpack --watch -c webpack.config.js",
9
10
  "update": "node tests/snapshots --update",
10
11
  "test": "node tests/snapshots --validate"
11
12
  },
@@ -20,11 +21,11 @@
20
21
  },
21
22
  "homepage": "https://github.com/TurboWarp/sb3fix#readme",
22
23
  "dependencies": {
23
- "@turbowarp/jszip": "^3.11.0"
24
+ "@turbowarp/jszip": "^3.11.1"
24
25
  },
25
26
  "devDependencies": {
26
27
  "copy-webpack-plugin": "^12.0.2",
27
- "webpack": "^5.90.3",
28
+ "webpack": "^5.96.1",
28
29
  "webpack-cli": "^5.1.4"
29
30
  }
30
31
  }
package/src/sb3fix.js CHANGED
@@ -67,7 +67,7 @@ const getKnownExtensions = (project) => {
67
67
  /**
68
68
  * @param {string|object} data project.json as a string or as a parsed object already. If object provided, it will be modified in-place.
69
69
  * @param {Options} [options]
70
- * @returns {object} Fixed project.json object. If an object was provided as `data`, the return value will be `data`.
70
+ * @returns {object} Fixed project.json object. If the `data` argument was an object, this will point to the same object.
71
71
  */
72
72
  const fixJSON = (data, options = {}) => {
73
73
  /**
@@ -219,8 +219,8 @@ const fixJSON = (data, options = {}) => {
219
219
  }
220
220
 
221
221
  // https://github.com/scratchfoundation/scratch-parser/blob/665f05d739a202d565a4af70a201909393d456b2/lib/sb3_definitions.json#L51
222
- const knownDataFormats = ['png', 'svg', 'jpeg', 'jpg', 'bmp', 'gif'];
223
- if (!knownDataFormats.includes(costume.dataFormat)) {
222
+ const knownCostumeFormats = ['png', 'svg', 'jpeg', 'jpg', 'bmp', 'gif'];
223
+ if (!knownCostumeFormats.includes(costume.dataFormat)) {
224
224
  if (typeof costume.md5ext === 'string' && costume.md5ext.endsWith('.svg')) {
225
225
  log(`costume ${i} is vector, had invalid dataFormat ${costume.dataFormat}`);
226
226
  costume.dataFormat = 'svg';
@@ -261,6 +261,13 @@ const fixJSON = (data, options = {}) => {
261
261
  throw new Error(`sound ${i} is not an object`);
262
262
  }
263
263
 
264
+ // https://github.com/scratchfoundation/scratch-parser/blob/665f05d739a202d565a4af70a201909393d456b2/lib/sb3_definitions.json#L81
265
+ const knownSoundFormats = ['wav', 'wave', 'mp3'];
266
+ if (!knownSoundFormats.includes(sound.dataFormat)) {
267
+ log(`sound ${i} had invalid dataFormat ${sound.dataFormat}`);
268
+ sound.dataFormat = 'mp3';
269
+ }
270
+
264
271
  if (typeof sound.name !== 'string') {
265
272
  log(`sound ${i} name was not a string`);
266
273
  sound.name = String(sound.name);
@@ -344,11 +351,10 @@ const fixJSON = (data, options = {}) => {
344
351
  fixTargetInPlace(target);
345
352
  }
346
353
 
347
- let stage;
348
354
  const allStages = targets.filter((target) => target.isStage);
349
355
  if (allStages.length === 0) {
350
356
  log('stage is missing; adding an empty one');
351
- stage = {
357
+ targets.unshift({
352
358
  isStage: true,
353
359
  name: 'Stage',
354
360
  variables: {},
@@ -373,22 +379,31 @@ const fixJSON = (data, options = {}) => {
373
379
  videoTransparency: 50,
374
380
  videoState: "on",
375
381
  textToSpeechLanguage: null
376
- };
377
- targets.unshift(stage);
378
- } else if (allStages.length === 1) {
379
- const stageIndex = targets.findIndex((target) => target.isStage);
380
- // stageIndex guaranteed to not be -1 by earlier filter check
381
- stage = targets[stageIndex];
382
- // stage must be the first target
383
- if (stageIndex !== 0) {
384
- log(`stage was at wrong index: ${stageIndex}`);
385
- targets.splice(stageIndex, 1);
382
+ });
383
+ } else {
384
+ // We will accept the first stage in targets as the real stage
385
+ const firstStageIndex = targets.findIndex((target) => target.isStage);
386
+
387
+ // Stage must be the first target
388
+ if (firstStageIndex !== 0) {
389
+ log(`stage was at wrong index: ${firstStageIndex}`);
390
+ const stage = targets[firstStageIndex];
391
+ targets.splice(firstStageIndex, 1);
386
392
  targets.unshift(stage);
387
393
  }
388
- } else {
389
- throw new Error(`wrong number of stages: ${allStages.length}`);
394
+
395
+ // Remove all the other stages
396
+ for (let i = targets.length - 1; i > 0; i--) {
397
+ if (targets[i].isStage) {
398
+ log(`removing extra stage at index ${i}`);
399
+ targets.splice(i, 1);
400
+ }
401
+ }
390
402
  }
391
403
 
404
+ // Above checks ensure this invariant holds
405
+ const stage = targets[0];
406
+
392
407
  // stage's name must match exactly
393
408
  if (stage.name !== 'Stage') {
394
409
  log(`stage had wrong name: ${stage.name}`);