Skip to content

Commit f095938

Browse files
authored
Merge pull request #39 from kchadha/sprite-validation
Add validation for sprite2 and sprite3 files
2 parents 5daad96 + 78ce54e commit f095938

23 files changed

+1136
-675
lines changed

index.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,22 @@ var validate = require('./lib/validate');
88
* Unpacks, parses, validates, and analyzes Scratch projects. If successful,
99
* will return a valid Scratch project object with appended metadata.
1010
* @param {Buffer | string} input Buffer or string representing project
11+
* @param {boolean} isSprite Whether this is a sprite (true) or whole project (false)
1112
* @param {Function} callback Returns error or project data
1213
*/
13-
module.exports = function (input, callback) {
14+
module.exports = function (input, isSprite, callback) {
1415
// First unpack the input (need this outside of the async waterfall so that
1516
// unpackedProject can be refered to again)
16-
unpack(input, function (err, unpackedProject) {
17+
unpack(input, isSprite, function (err, unpackedProject) {
1718
if (err) return callback(err);
1819

1920
async.waterfall([
2021
function (cb) {
2122
parse(unpackedProject[0], cb);
2223
},
23-
validate
24+
// TODO is there a better way to pass this arg
25+
// than partially applying this funciton?
26+
validate.bind(null, isSprite)
2427
], function (error, validatedInput) {
2528
// One more callback wrapper so that we can re-package everything
2629
// with the possible zip returned from unpack

lib/parse.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
* @return {void}
99
*/
1010
module.exports = function (input, callback) {
11+
var result;
1112
try {
12-
var result = JSON.parse(input);
13-
callback(null, result);
13+
result = JSON.parse(input);
1414
} catch (e) {
1515
return callback(e.toString());
1616
}
17+
return callback(null, result);
1718
};

lib/sb2_definitions.json

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
{
2+
"$id": "https://scratch.mit.edu/sb2_definitions.json",
3+
"$schema": "http://json-schema.org/schema#",
4+
"description": "Scratch 2.0 Project and Sprite Definitions",
5+
"definitions": {
6+
"scripts": {
7+
"type": "array"
8+
},
9+
"sounds": {
10+
"type": "array",
11+
"properties": {
12+
"soundName": {
13+
"type": "string"
14+
},
15+
"soundID": {
16+
"type": "number"
17+
},
18+
"md5": {
19+
"type": "string"
20+
},
21+
"sampleCount": {
22+
"type": "number"
23+
},
24+
"rate": {
25+
"type": "number"
26+
},
27+
"format": {
28+
"type": "string"
29+
}
30+
},
31+
"required": [
32+
"soundName",
33+
"soundID",
34+
"md5",
35+
"sampleCount",
36+
"rate",
37+
"format"
38+
]
39+
},
40+
"costumes": {
41+
"type": "array",
42+
"properties": {
43+
"costumeName": {
44+
"type": "string"
45+
},
46+
"baseLayerID": {
47+
"type": "number"
48+
},
49+
"baseLayerMD5": {
50+
"type": "string"
51+
},
52+
"bitmapResolution": {
53+
"type": "number"
54+
},
55+
"rotationCenterX": {
56+
"type": "number"
57+
},
58+
"rotationCenterY": {
59+
"type": "number"
60+
}
61+
},
62+
"required": [
63+
"costumeName",
64+
"baseLayerID",
65+
"baseLayerMD5",
66+
"bitmapResolution",
67+
"rotationCenterX",
68+
"rotationCenterY"
69+
]
70+
},
71+
"variables": {
72+
"type": "array",
73+
"properties": {
74+
"name": {
75+
"type": "string"
76+
},
77+
"value": {
78+
"type": "string"
79+
},
80+
"isPersistent": {
81+
"type": "boolean"
82+
}
83+
},
84+
"required": [
85+
"name",
86+
"value"
87+
]
88+
},
89+
"sprite_object": {
90+
"type": "object",
91+
"properties": {
92+
"objName": {
93+
"type": "string"
94+
},
95+
"variables": {"$ref": "#/definitions/variables"},
96+
"sounds": {"$ref":"#/definitions/sounds"},
97+
"costumes": {"$ref":"#/definitions/costumes"},
98+
"currentCostumeIndex": {
99+
"type": "number",
100+
"minimum": 0
101+
}
102+
},
103+
"additionalProperties": true,
104+
"required": [
105+
"objName",
106+
"sounds",
107+
"costumes",
108+
"currentCostumeIndex"
109+
]
110+
},
111+
"stage_child": {
112+
"type": "object",
113+
"description": "A child of the stage, can be a sprite or a monitor"
114+
},
115+
"stage_object" : {
116+
"type": "object",
117+
"properties": {
118+
"objName": {
119+
"type": "string"
120+
},
121+
"variables": {"$ref": "#/definitions/variables"},
122+
"lists": {
123+
"type": "array",
124+
"properties": {
125+
"listName": {
126+
"type": "string"
127+
},
128+
"contents": {
129+
"type": "array"
130+
},
131+
"isPersistent": {
132+
"type": "boolean"
133+
},
134+
"x": {
135+
"type": "number"
136+
},
137+
"y": {
138+
"type": "number"
139+
},
140+
"width": {
141+
"type": "number"
142+
},
143+
"height": {
144+
"type": "number"
145+
},
146+
"visible": {
147+
"type": "boolean"
148+
}
149+
},
150+
"required": [
151+
"listName",
152+
"contents"
153+
]
154+
},
155+
"scripts": {"$ref": "#/definitions/scripts"},
156+
"sounds": {"$ref": "#/definitions/sounds"},
157+
"costumes": {"$ref": "#/definitions/costumes"},
158+
"currentCostumeIndex": {
159+
"type": "number",
160+
"minimum": 0
161+
},
162+
"penLayerMD5": {
163+
"oneOf":[
164+
{"type": "string"},
165+
{"type": "null"}
166+
]
167+
},
168+
"penLayerID": {
169+
"type": "number",
170+
"minimum": -1
171+
},
172+
"tempoBPM": {
173+
"type": "number"
174+
},
175+
"videoAlpha": {
176+
"type": "number",
177+
"minimum": 0,
178+
"maximum": 1
179+
},
180+
"children": {
181+
"type": "array",
182+
"items": {"$ref": "#/definitions/stage_child"}
183+
}
184+
},
185+
"required": [
186+
"objName",
187+
"costumes",
188+
"currentCostumeIndex",
189+
"penLayerMD5",
190+
"tempoBPM",
191+
"children"
192+
]
193+
}
194+
}
195+
}

0 commit comments

Comments
 (0)