@turbowarp/sb3fix 0.2.0 → 0.2.2

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/sb3fix.js +54 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turbowarp/sb3fix",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Fix corrupted Scratch projects",
5
5
  "main": "src/sb3fix.js",
6
6
  "scripts": {
package/src/sb3fix.js CHANGED
@@ -134,7 +134,7 @@ const fixJSON = (data, options = {}) => {
134
134
  /**
135
135
  * @param {unknown[]} native
136
136
  */
137
- const fixNativeInPlace = (native) => {
137
+ const fixCompressedNativeInPlace = (native) => {
138
138
  if (!Array.isArray(native)) {
139
139
  throw new Error('native is not an array');
140
140
  }
@@ -144,10 +144,13 @@ const fixJSON = (data, options = {}) => {
144
144
  throw new Error('native type is not a number');
145
145
  }
146
146
  switch (type) {
147
- case 12: // Variable: [12, variable name, variable id]
148
- case 13: // List: [13, list name, list id]
149
- if (native.length !== 3) {
150
- throw new Error('variable or list native is of wrong length');
147
+ // Variable: [12, variable name, variable id, x?, y?]
148
+ // List: [13, list name, list id, x?, y?]
149
+ // x and y only present if the native is a top-level block
150
+ case 12:
151
+ case 13: {
152
+ if (native.length !== 3 && native.length !== 5) {
153
+ throw new Error(`Variable or list native is of unexpected length: ${native.length}`);
151
154
  }
152
155
  const name = native[1];
153
156
  if (typeof name !== 'string') {
@@ -155,6 +158,7 @@ const fixJSON = (data, options = {}) => {
155
158
  native[1] = String(native[1]);
156
159
  }
157
160
  break;
161
+ }
158
162
  }
159
163
  };
160
164
 
@@ -164,7 +168,7 @@ const fixJSON = (data, options = {}) => {
164
168
  */
165
169
  const fixBlockInPlace = (id, block) => {
166
170
  if (Array.isArray(block)) {
167
- fixNativeInPlace(block);
171
+ fixCompressedNativeInPlace(block);
168
172
  } else if (isObject(block)) {
169
173
  const inputs = block.inputs;
170
174
  if (!isObject(inputs)) {
@@ -176,7 +180,7 @@ const fixJSON = (data, options = {}) => {
176
180
  }
177
181
  for (let i = 1; i < input.length; i++) {
178
182
  if (Array.isArray(input[i])) {
179
- fixNativeInPlace(input[i]);
183
+ fixCompressedNativeInPlace(input[i]);
180
184
  }
181
185
  }
182
186
  }
@@ -326,23 +330,55 @@ const fixJSON = (data, options = {}) => {
326
330
  fixTargetInPlace(target);
327
331
  }
328
332
 
333
+ let stage;
329
334
  const allStages = targets.filter((target) => target.isStage);
330
- if (allStages.length !== 1) {
331
- throw new Error(`wrong number of stages: ${allStages.length}`);
332
- }
333
- const stageIndex = targets.findIndex((target) => target.isStage);
334
- // stageIndex guaranteed to not be -1 by earlier check
335
- const stage = targets[stageIndex];
336
- // stage must be the first target
337
- if (stageIndex !== 0) {
338
- log('stage was not at start');
339
- targets.splice(stageIndex, 1);
335
+ if (allStages.length === 0) {
336
+ log('stage is missing; adding an empty one');
337
+ stage = {
338
+ isStage: true,
339
+ name: 'Stage',
340
+ variables: {},
341
+ lists: {},
342
+ broadcasts: {},
343
+ blocks: {},
344
+ currentCostume: 0,
345
+ costumes: [
346
+ {
347
+ name: 'backdrop1',
348
+ dataFormat: 'svg',
349
+ assetId: 'cd21514d0531fdffb22204e0ec5ed84a',
350
+ md5ext: 'cd21514d0531fdffb22204e0ec5ed84a.svg',
351
+ rotationCenterX: 240,
352
+ rotationCenterY: 180
353
+ }
354
+ ],
355
+ sounds: [],
356
+ volume: 100,
357
+ layerOrder: 0,
358
+ tempo: 60,
359
+ videoTransparency: 50,
360
+ videoState: "on",
361
+ textToSpeechLanguage: null
362
+ };
340
363
  targets.unshift(stage);
364
+ } else if (allStages.length === 1) {
365
+ const stageIndex = targets.findIndex((target) => target.isStage);
366
+ // stageIndex guaranteed to not be -1 by earlier filter check
367
+ stage = targets[stageIndex];
368
+ // stage must be the first target
369
+ if (stageIndex !== 0) {
370
+ log(`stage was at wrong index: ${stageIndex}`);
371
+ targets.splice(stageIndex, 1);
372
+ targets.unshift(stage);
373
+ }
374
+ } else {
375
+ throw new Error(`wrong number of stages: ${allStages.length}`);
341
376
  }
377
+
342
378
  // stage's name must match exactly
343
379
  if (stage.name !== 'Stage') {
380
+ log(`stage had wrong name: ${stage.name}`);
344
381
  stage.name = 'Stage';
345
- log('stage had wrong name');
346
382
  }
347
383
 
348
384
  const knownExtensions = getKnownExtensions(project);