@turbowarp/sb3fix 0.3.3 → 0.3.5

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 +4 -4
  2. package/src/sb3fix.js +68 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turbowarp/sb3fix",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Fix corrupted Scratch projects",
5
5
  "main": "src/sb3fix.js",
6
6
  "scripts": {
@@ -24,8 +24,8 @@
24
24
  "@turbowarp/jszip": "^3.11.1"
25
25
  },
26
26
  "devDependencies": {
27
- "copy-webpack-plugin": "^12.0.2",
28
- "webpack": "^5.96.1",
29
- "webpack-cli": "^5.1.4"
27
+ "copy-webpack-plugin": "^13.0.0",
28
+ "webpack": "^5.98.0",
29
+ "webpack-cli": "^6.0.1"
30
30
  }
31
31
  }
package/src/sb3fix.js CHANGED
@@ -144,6 +144,19 @@ const fixJSON = (data, options = {}) => {
144
144
  throw new Error('native type is not a number');
145
145
  }
146
146
  switch (type) {
147
+ // Color: [9, hex color]
148
+ case 9: {
149
+ if (native.length !== 2) {
150
+ throw new Error(`Color native is of unexpected length: ${native.length}`);
151
+ }
152
+ const color = native[1];
153
+ if (typeof color !== 'string' || !/^#[a-f0-9]{6}$/i.test(color)) {
154
+ log('color native had invalid value');
155
+ native[1] = '#000000';
156
+ }
157
+ break;
158
+ }
159
+
147
160
  // Variable: [12, variable name, variable id, x?, y?]
148
161
  // List: [13, list name, list id, x?, y?]
149
162
  // x and y only present if the native is a top-level block
@@ -199,6 +212,29 @@ const fixJSON = (data, options = {}) => {
199
212
  }
200
213
  };
201
214
 
215
+ /**
216
+ * @param {string} id
217
+ * @param {unknown} comment
218
+ */
219
+ const fixCommentInPlace = (id, comment) => {
220
+ if (!isObject(comment)) {
221
+ throw new Error('comment is not an object');
222
+ }
223
+
224
+ if (typeof comment.text !== 'string') {
225
+ throw new Error('comment text is not a string');
226
+ }
227
+
228
+ // Scratch requires comments to not exceed 8000 characters.
229
+ // We'll store the excess in .extraText so the text won't be truncated if opened in TurboWarp.
230
+ const MAX_LENGTH = 8000;
231
+ if (comment.text.length > MAX_LENGTH) {
232
+ log(`comment ${id} had length ${comment.text.length}`);
233
+ comment.extraText = comment.text.substring(MAX_LENGTH);
234
+ comment.text = comment.text.substring(0, MAX_LENGTH);
235
+ }
236
+ };
237
+
202
238
  /**
203
239
  * @param {unknown} target
204
240
  */
@@ -287,6 +323,14 @@ const fixJSON = (data, options = {}) => {
287
323
  fixBlockInPlace(blockId, block);
288
324
  }
289
325
 
326
+ // Comments are not required
327
+ const comments = target.comments;
328
+ if (comments) {
329
+ for (const [commentId, comment] of Object.entries(comments)) {
330
+ fixCommentInPlace(commentId, comment);
331
+ }
332
+ }
333
+
290
334
  const variables = target.variables;
291
335
  if (!isObject(variables)) {
292
336
  throw new Error('variables is not an object');
@@ -314,6 +358,30 @@ const fixJSON = (data, options = {}) => {
314
358
  target.layerOrder = 1;
315
359
  }
316
360
  }
361
+
362
+ const ROTATION_STYLES = [
363
+ 'all around',
364
+ 'don\'t rotate',
365
+ 'left-right'
366
+ ];
367
+ if (!target.isStage && !ROTATION_STYLES.includes(target.rotationStyle)) {
368
+ log(`sprite had invalid rotation style ${target.rotationStyle}`);
369
+ target.rotationStyle = 'all around';
370
+ }
371
+
372
+ if (!target.isStage) {
373
+ const x = target.x;
374
+ if (typeof x !== 'number') {
375
+ log(`target x was ${typeof x}: ${x}`);
376
+ target.x = +x || 0;
377
+ }
378
+
379
+ const y = target.y;
380
+ if (typeof y !== 'number') {
381
+ log(`target y was ${typeof y}: ${y}`);
382
+ target.y = +y || 0;
383
+ }
384
+ }
317
385
  };
318
386
 
319
387
  /**