mirror of
https://github.com/scratchfoundation/scratch-parser.git
synced 2025-08-28 22:18:45 -04:00
feat(schemas): add support for sprite files for 2.0 and 3.0
refactor schemas to support sprite2 and sprite3 files, while reusing rules in common with sb2 and sb3 files BREAKING CHANGE: Change to main API which now takes an additional boolean argument indicating whether a sprite or project is being validated
This commit is contained in:
parent
5daad968a4
commit
b808e7447f
11 changed files with 759 additions and 616 deletions
7
index.js
7
index.js
|
@ -7,20 +7,21 @@ var validate = require('./lib/validate');
|
||||||
/**
|
/**
|
||||||
* Unpacks, parses, validates, and analyzes Scratch projects. If successful,
|
* Unpacks, parses, validates, and analyzes Scratch projects. If successful,
|
||||||
* will return a valid Scratch project object with appended metadata.
|
* will return a valid Scratch project object with appended metadata.
|
||||||
|
* @param {boolean} isSprite Whether this is a sprite (true) or whole project (false)
|
||||||
* @param {Buffer | string} input Buffer or string representing project
|
* @param {Buffer | string} input Buffer or string representing project
|
||||||
* @param {Function} callback Returns error or project data
|
* @param {Function} callback Returns error or project data
|
||||||
*/
|
*/
|
||||||
module.exports = function (input, callback) {
|
module.exports = function (isSprite, input, callback) {
|
||||||
// First unpack the input (need this outside of the async waterfall so that
|
// First unpack the input (need this outside of the async waterfall so that
|
||||||
// unpackedProject can be refered to again)
|
// unpackedProject can be refered to again)
|
||||||
unpack(input, function (err, unpackedProject) {
|
unpack(isSprite, input, function (err, unpackedProject) {
|
||||||
if (err) return callback(err);
|
if (err) return callback(err);
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (cb) {
|
function (cb) {
|
||||||
parse(unpackedProject[0], cb);
|
parse(unpackedProject[0], cb);
|
||||||
},
|
},
|
||||||
validate
|
validate.bind(null, isSprite)
|
||||||
], function (error, validatedInput) {
|
], function (error, validatedInput) {
|
||||||
// One more callback wrapper so that we can re-package everything
|
// One more callback wrapper so that we can re-package everything
|
||||||
// with the possible zip returned from unpack
|
// with the possible zip returned from unpack
|
||||||
|
|
|
@ -8,10 +8,11 @@
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
module.exports = function (input, callback) {
|
module.exports = function (input, callback) {
|
||||||
|
var result;
|
||||||
try {
|
try {
|
||||||
var result = JSON.parse(input);
|
result = JSON.parse(input);
|
||||||
callback(null, result);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return callback(e.toString());
|
return callback(e.toString());
|
||||||
}
|
}
|
||||||
|
return callback(null, result);
|
||||||
};
|
};
|
||||||
|
|
191
lib/sb2_definitions.json
Normal file
191
lib/sb2_definitions.json
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
{
|
||||||
|
"$id": "https://scratch.mit.edu/sb2_definitions.json",
|
||||||
|
"$schema": "http://json-schema.org/schema#",
|
||||||
|
"description": "Scratch 2.0 Project and Sprite Definitions",
|
||||||
|
"definitions": {
|
||||||
|
"scripts": {
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"sounds": {
|
||||||
|
"type": "array",
|
||||||
|
"properties": {
|
||||||
|
"soundName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"soundID": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"md5": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sampleCount": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"rate": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"soundName",
|
||||||
|
"soundID",
|
||||||
|
"md5",
|
||||||
|
"sampleCount",
|
||||||
|
"rate",
|
||||||
|
"format"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"costumes": {
|
||||||
|
"type": "array",
|
||||||
|
"properties": {
|
||||||
|
"costumeName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"baseLayerID": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"baseLayerMD5": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"bitmapResolution": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"rotationCenterX": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"rotationCenterY": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"costumeName",
|
||||||
|
"baseLayerID",
|
||||||
|
"baseLayerMD5",
|
||||||
|
"bitmapResolution",
|
||||||
|
"rotationCenterX",
|
||||||
|
"rotationCenterY"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"variables": {
|
||||||
|
"type": "array",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"isPersistent": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sprite_object": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"objName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"variables": {"$ref": "#/definitions/variables"},
|
||||||
|
"sounds": {"$ref":"#/definitions/sounds"},
|
||||||
|
"costumes": {"$ref":"#/definitions/costumes"},
|
||||||
|
"currentCostumeIndex": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": true,
|
||||||
|
"required": [
|
||||||
|
"objName",
|
||||||
|
"sounds",
|
||||||
|
"costumes",
|
||||||
|
"currentCostumeIndex"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"stage_object" : {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"objName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"variables": {"$ref": "#/definitions/variables"},
|
||||||
|
"lists": {
|
||||||
|
"type": "array",
|
||||||
|
"properties": {
|
||||||
|
"listName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"contents": {
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"isPersistent": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"x": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"y": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"width": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"height": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"visible": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"listName",
|
||||||
|
"contents"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": {"$ref": "#/definitions/scripts"},
|
||||||
|
"sounds": {"$ref": "#/definitions/sounds"},
|
||||||
|
"costumes": {"$ref": "#/definitions/costumes"},
|
||||||
|
"currentCostumeIndex": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"penLayerMD5": {
|
||||||
|
"oneOf":[
|
||||||
|
{"type": "string"},
|
||||||
|
{"type": "null"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"penLayerID": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": -1
|
||||||
|
},
|
||||||
|
"tempoBPM": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"videoAlpha": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 1
|
||||||
|
},
|
||||||
|
"children": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/definitions/sprite_object"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"objName",
|
||||||
|
"costumes",
|
||||||
|
"currentCostumeIndex",
|
||||||
|
"penLayerMD5",
|
||||||
|
"tempoBPM",
|
||||||
|
"children"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,207 +1,54 @@
|
||||||
{
|
{
|
||||||
"$id": "https://scratch.mit.edu",
|
"$id": "https://scratch.mit.edu/sb2_schema.json",
|
||||||
"description": "Scratch project schema",
|
"$schema": "http://json-schema.org/schema#",
|
||||||
|
"description": "Scratch 2.0 project schema",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"allOf": [
|
||||||
"objName": {
|
{"$ref": "sb2_definitions.json#/definitions/stage_object"},
|
||||||
"type": "string"
|
{
|
||||||
},
|
|
||||||
"variables": {
|
|
||||||
"type": "array",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"isPersistent": {
|
|
||||||
"type": "boolean"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"name",
|
|
||||||
"value"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lists": {
|
|
||||||
"type": "array",
|
|
||||||
"properties": {
|
|
||||||
"listName": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"contents": {
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"isPersistent": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"x": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"y": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"width": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"height": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"visible": {
|
|
||||||
"type": "boolean"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"listName",
|
|
||||||
"contents"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"sounds": {
|
|
||||||
"type": "array",
|
|
||||||
"properties": {
|
|
||||||
"soundName": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"soundID": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"md5": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sampleCount": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"rate": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"format": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"soundName",
|
|
||||||
"soundID",
|
|
||||||
"md5",
|
|
||||||
"sampleCount",
|
|
||||||
"rate",
|
|
||||||
"format"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"costumes": {
|
|
||||||
"type": "array",
|
|
||||||
"properties": {
|
|
||||||
"costumeName": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"baseLayerID": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"baseLayerMD5": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"bitmapResolution": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"rotationCenterX": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"rotationCenterY": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"costumeName",
|
|
||||||
"baseLayerID",
|
|
||||||
"baseLayerMD5",
|
|
||||||
"bitmapResolution",
|
|
||||||
"rotationCenterX",
|
|
||||||
"rotationCenterY"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"currentCostumeIndex": {
|
|
||||||
"type": "number",
|
|
||||||
"minimum": 0
|
|
||||||
},
|
|
||||||
"penLayerMD5": {
|
|
||||||
"oneOf":[
|
|
||||||
{"type": "string"},
|
|
||||||
{"type": "null"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"penLayerID": {
|
|
||||||
"type": "number",
|
|
||||||
"minimum": -1
|
|
||||||
},
|
|
||||||
"tempoBPM": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"videoAlpha": {
|
|
||||||
"type": "number",
|
|
||||||
"minimum": 0,
|
|
||||||
"maximum": 1
|
|
||||||
},
|
|
||||||
"children": {
|
|
||||||
"type": "array",
|
|
||||||
"properties": {},
|
|
||||||
"required": [
|
|
||||||
"objName",
|
|
||||||
"sounds",
|
|
||||||
"costumes",
|
|
||||||
"currentCostumeIndex"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"info": {
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"flashVersion": {
|
"info": {
|
||||||
"type": "string"
|
"type": "object",
|
||||||
},
|
|
||||||
"swfVersion": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"userAgent": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"videoOn": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"savedExtensions": {
|
|
||||||
"type": "array",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"extensionName": {
|
"flashVersion": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"blockSpecs": {
|
"swfVersion": {
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"menus": {
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"javascriptURL": {
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"userAgent": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"videoOn": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"savedExtensions": {
|
||||||
|
"type": "array",
|
||||||
|
"properties": {
|
||||||
|
"extensionName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"blockSpecs": {
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"menus": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"javascriptURL": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"extensionName",
|
||||||
|
"blockSpecs",
|
||||||
|
"menus",
|
||||||
|
"javascriptURL"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"required": [
|
|
||||||
"extensionName",
|
|
||||||
"blockSpecs",
|
|
||||||
"menus",
|
|
||||||
"javascriptURL"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"objName",
|
|
||||||
"costumes",
|
|
||||||
"currentCostumeIndex",
|
|
||||||
"penLayerMD5",
|
|
||||||
"tempoBPM",
|
|
||||||
"children",
|
|
||||||
"info"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
404
lib/sb3_definitions.json
Normal file
404
lib/sb3_definitions.json
Normal file
|
@ -0,0 +1,404 @@
|
||||||
|
{
|
||||||
|
"$id": "https://scratch.mit.edu/sb3_definitions.json",
|
||||||
|
"$schema": "http://json-schema.org/schema#",
|
||||||
|
"description": "Scratch 3.0 Project and Sprite Schema Definitions",
|
||||||
|
"definitions": {
|
||||||
|
"optionalString": {
|
||||||
|
"oneOf": [
|
||||||
|
{"type": "string"},
|
||||||
|
{"type": "null"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"boolOrBoolString": {
|
||||||
|
"oneOf": [
|
||||||
|
{"type": "string",
|
||||||
|
"enum": ["true", "false"]},
|
||||||
|
{"type": "boolean"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"stringOrNumber": {
|
||||||
|
"oneOf": [
|
||||||
|
{"type": "string"},
|
||||||
|
{"type": "number"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scalarVal": {
|
||||||
|
"oneOf": [
|
||||||
|
{"$ref":"#/definitions/stringOrNumber"},
|
||||||
|
{"type": "boolean"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"assetId": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[a-fA-F0-9]{32}$"
|
||||||
|
},
|
||||||
|
"costume": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"assetId": { "$ref": "#/definitions/assetId"},
|
||||||
|
"bitmapResolution": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"dataFormat": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["png", "svg", "jpeg", "jpg", "bmp", "gif"]
|
||||||
|
},
|
||||||
|
"md5ext": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[a-fA-F0-9]{32}\\.[a-zA-Z]+$"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"rotationCenterX": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "This property is not required, but is highly recommended."
|
||||||
|
},
|
||||||
|
"rotationCenterY": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "This property is not required, but is highly recommended."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"assetId",
|
||||||
|
"dataFormat",
|
||||||
|
"name"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sound": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"assetId": { "$ref": "#/definitions/assetId"},
|
||||||
|
"dataFormat": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["wav", "wave", "mp3"]
|
||||||
|
},
|
||||||
|
"md5ext": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[a-fA-F0-9]{32}\\.[a-zA-Z0-9]+$"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"rate": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"sampleCount": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"assetId",
|
||||||
|
"dataFormat",
|
||||||
|
"name"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scalar_variable": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{"type": "string", "description": "name of the variable"},
|
||||||
|
{"$ref":"#/definitions/scalarVal", "description": "value of the variable"}
|
||||||
|
],
|
||||||
|
"additionalItems": {"type": "boolean", "enum": [true], "description": "Whether this is a cloud variable"},
|
||||||
|
"maxItems": 3
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{"type":"string", "description": "name of the list"},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"description": "contents of the list",
|
||||||
|
"items": {"$ref":"#/definitions/scalarVal"}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalItems": false
|
||||||
|
},
|
||||||
|
"broadcast_message": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "the message being broadcasted"
|
||||||
|
},
|
||||||
|
"num_primitive": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"enum": [4,5,6,7,8]
|
||||||
|
},
|
||||||
|
{"$ref":"#/definitions/stringOrNumber"}
|
||||||
|
],
|
||||||
|
"additionalItems": false
|
||||||
|
},
|
||||||
|
"color_primitive": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"enum": [9]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^#[a-fA-F0-9]{6}$"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalItems": false
|
||||||
|
},
|
||||||
|
"text_primitive": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"enum": [10]
|
||||||
|
},
|
||||||
|
{"$ref":"#/definitions/stringOrNumber"}
|
||||||
|
],
|
||||||
|
"additionalItems": false
|
||||||
|
},
|
||||||
|
"broadcast_primitive": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"enum": [11]
|
||||||
|
},
|
||||||
|
{"type": "string", "description": "broadcast message"},
|
||||||
|
{"type": "string", "description": "broadcast message id"}
|
||||||
|
],
|
||||||
|
"additionalItems": false
|
||||||
|
},
|
||||||
|
"variable_primitive": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"enum": [12]
|
||||||
|
},
|
||||||
|
{"type": "string", "description": "variable name"},
|
||||||
|
{"type": "string", "description": "variable id"}
|
||||||
|
],
|
||||||
|
"additionalItems": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"minItems": 3,
|
||||||
|
"maxItems": 5
|
||||||
|
},
|
||||||
|
"list_primitive": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"enum": [13]
|
||||||
|
},
|
||||||
|
{"type": "string", "description": "list name"},
|
||||||
|
{"type": "string", "description": "list id"}
|
||||||
|
],
|
||||||
|
"additionalItems": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"minItems": 3,
|
||||||
|
"maxItems": 5
|
||||||
|
},
|
||||||
|
"topLevelPrimitive": {
|
||||||
|
"oneOf": [
|
||||||
|
{"$ref":"#/definitions/variable_primitive"},
|
||||||
|
{"$ref":"#/definitions/list_primitive"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"inputPrimitive": {
|
||||||
|
"oneOf": [
|
||||||
|
{"$ref":"#/definitions/num_primitive"},
|
||||||
|
{"$ref":"#/definitions/color_primitive"},
|
||||||
|
{"$ref":"#/definitions/text_primitive"},
|
||||||
|
{"$ref":"#/definitions/broadcast_primitive"},
|
||||||
|
{"$ref":"#/definitions/variable_primitive"},
|
||||||
|
{"$ref":"#/definitions/list_primitive"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"block": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"opcode": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"inputs": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type":"number",
|
||||||
|
"enum":[1,2,3],
|
||||||
|
"description": "1 = unobscured shadow, 2 = no shadow, 3 = obscured shadow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalItems": {
|
||||||
|
"oneOf": [
|
||||||
|
{"$ref":"#/definitions/optionalString"},
|
||||||
|
{"$ref":"#/definitions/inputPrimitive"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"next": {"$ref":"#/definitions/optionalString"},
|
||||||
|
"topLevel": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"parent": {"$ref":"#/definitions/optionalString"},
|
||||||
|
"shadow": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"x": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"y": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"mutation": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"tagName": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["mutation"]
|
||||||
|
},
|
||||||
|
"children": {
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"proccode": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"argumentids": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"warp": {"$ref":"#/definitions/boolOrBoolString"},
|
||||||
|
"hasnext": {"$ref":"#/definitions/boolOrBoolString"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"opcode"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"stage": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Description of property (and/or property/value pairs) that are unique to the stage.",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["Stage"]
|
||||||
|
},
|
||||||
|
"isStage": {
|
||||||
|
"type": "boolean",
|
||||||
|
"enum": [true]
|
||||||
|
},
|
||||||
|
"tempo": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"videoTransparency": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"videoState": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["on", "off", "on-flipped"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"isStage"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sprite": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Description of property (and/or property/value pairs) for sprites.",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"not": {"enum": ["Stage", "stage"]}
|
||||||
|
},
|
||||||
|
"isStage": {
|
||||||
|
"type": "boolean",
|
||||||
|
"enum": [false]
|
||||||
|
},
|
||||||
|
"visible": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"x": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"y": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"direction": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"draggable": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"rotationStyle": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["all around", "don't rotate", "left-right"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"isStage"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"target": {
|
||||||
|
"type": "object",
|
||||||
|
"description" : "Properties common to both Scratch 3.0 Stage and Sprite",
|
||||||
|
"properties": {
|
||||||
|
"currentCostume": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"blocks": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"oneOf": [
|
||||||
|
{"$ref":"#/definitions/block"},
|
||||||
|
{"$ref":"#/definitions/topLevelPrimitive"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"variables": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {"$ref":"#/definitions/scalar_variable"}
|
||||||
|
},
|
||||||
|
"lists": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {"$ref":"#/definitions/list"}
|
||||||
|
},
|
||||||
|
"broadcasts": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {"$ref":"#/definitions/broadcast_message"}
|
||||||
|
},
|
||||||
|
"costumes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref":"#/definitions/costume"},
|
||||||
|
"minItems": 1,
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"sounds": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref":"#/definitions/sound"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"volume": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"variables",
|
||||||
|
"costumes",
|
||||||
|
"sounds",
|
||||||
|
"blocks"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,410 +2,6 @@
|
||||||
"$id": "https://scratch.mit.edu/sb3_schema.json",
|
"$id": "https://scratch.mit.edu/sb3_schema.json",
|
||||||
"$schema": "http://json-schema.org/schema#",
|
"$schema": "http://json-schema.org/schema#",
|
||||||
"description": "Scratch 3.0 Project Schema",
|
"description": "Scratch 3.0 Project Schema",
|
||||||
"definitions": {
|
|
||||||
"optionalString": {
|
|
||||||
"oneOf": [
|
|
||||||
{"type": "string"},
|
|
||||||
{"type": "null"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"boolOrBoolString": {
|
|
||||||
"oneOf": [
|
|
||||||
{"type": "string",
|
|
||||||
"enum": ["true", "false"]},
|
|
||||||
{"type": "boolean"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stringOrNumber": {
|
|
||||||
"oneOf": [
|
|
||||||
{"type": "string"},
|
|
||||||
{"type": "number"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"scalarVal": {
|
|
||||||
"oneOf": [
|
|
||||||
{"$ref":"#/definitions/stringOrNumber"},
|
|
||||||
{"type": "boolean"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"assetId": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[a-fA-F0-9]{32}$"
|
|
||||||
},
|
|
||||||
"costume": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"assetId": { "$ref": "#/definitions/assetId"},
|
|
||||||
"bitmapResolution": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"dataFormat": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["png", "svg", "jpeg", "jpg", "bmp", "gif"]
|
|
||||||
},
|
|
||||||
"md5ext": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[a-fA-F0-9]{32}\\.[a-zA-Z]+$"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"rotationCenterX": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"rotationCenterY": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"assetId",
|
|
||||||
"dataFormat",
|
|
||||||
"name",
|
|
||||||
"rotationCenterX",
|
|
||||||
"rotationCenterY"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sound": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"assetId": { "$ref": "#/definitions/assetId"},
|
|
||||||
"dataFormat": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["wav", "wave", "mp3"]
|
|
||||||
},
|
|
||||||
"format": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["", "adpcm"]
|
|
||||||
},
|
|
||||||
"md5ext": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[a-fA-F0-9]{32}\\.[a-zA-Z0-9]+$"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"rate": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"sampleCount": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"assetId",
|
|
||||||
"dataFormat",
|
|
||||||
"format",
|
|
||||||
"name"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"scalar_variable": {
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{"type": "string", "description": "name of the variable"},
|
|
||||||
{"$ref":"#/definitions/scalarVal", "description": "value of the variable"}
|
|
||||||
],
|
|
||||||
"additionalItems": {"type": "boolean", "enum": [true], "description": "Whether this is a cloud variable"},
|
|
||||||
"maxItems": 3
|
|
||||||
},
|
|
||||||
"list": {
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{"type":"string", "description": "name of the list"},
|
|
||||||
{
|
|
||||||
"type": "array",
|
|
||||||
"description": "contents of the list",
|
|
||||||
"items": {"$ref":"#/definitions/scalarVal"}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"additionalItems": false
|
|
||||||
},
|
|
||||||
"broadcast_message": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "the message being broadcasted"
|
|
||||||
},
|
|
||||||
"num_primitive": {
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"type": "number",
|
|
||||||
"enum": [4,5,6,7,8]
|
|
||||||
},
|
|
||||||
{"$ref":"#/definitions/stringOrNumber"}
|
|
||||||
],
|
|
||||||
"additionalItems": false
|
|
||||||
},
|
|
||||||
"color_primitive": {
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"type": "number",
|
|
||||||
"enum": [9]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^#[a-fA-F0-9]{6}$"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"additionalItems": false
|
|
||||||
},
|
|
||||||
"text_primitive": {
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"type": "number",
|
|
||||||
"enum": [10]
|
|
||||||
},
|
|
||||||
{"$ref":"#/definitions/stringOrNumber"}
|
|
||||||
],
|
|
||||||
"additionalItems": false
|
|
||||||
},
|
|
||||||
"broadcast_primitive": {
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"type": "number",
|
|
||||||
"enum": [11]
|
|
||||||
},
|
|
||||||
{"type": "string", "description": "broadcast message"},
|
|
||||||
{"type": "string", "description": "broadcast message id"}
|
|
||||||
],
|
|
||||||
"additionalItems": false
|
|
||||||
},
|
|
||||||
"variable_primitive": {
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"type": "number",
|
|
||||||
"enum": [12]
|
|
||||||
},
|
|
||||||
{"type": "string", "description": "variable name"},
|
|
||||||
{"type": "string", "description": "variable id"}
|
|
||||||
],
|
|
||||||
"additionalItems": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"minItems": 3,
|
|
||||||
"maxItems": 5
|
|
||||||
},
|
|
||||||
"list_primitive": {
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"type": "number",
|
|
||||||
"enum": [13]
|
|
||||||
},
|
|
||||||
{"type": "string", "description": "list name"},
|
|
||||||
{"type": "string", "description": "list id"}
|
|
||||||
],
|
|
||||||
"additionalItems": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"minItems": 3,
|
|
||||||
"maxItems": 5
|
|
||||||
},
|
|
||||||
"topLevelPrimitive": {
|
|
||||||
"oneOf": [
|
|
||||||
{"$ref":"#/definitions/variable_primitive"},
|
|
||||||
{"$ref":"#/definitions/list_primitive"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"inputPrimitive": {
|
|
||||||
"oneOf": [
|
|
||||||
{"$ref":"#/definitions/num_primitive"},
|
|
||||||
{"$ref":"#/definitions/color_primitive"},
|
|
||||||
{"$ref":"#/definitions/text_primitive"},
|
|
||||||
{"$ref":"#/definitions/broadcast_primitive"},
|
|
||||||
{"$ref":"#/definitions/variable_primitive"},
|
|
||||||
{"$ref":"#/definitions/list_primitive"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"block": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"opcode": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"inputs": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"type":"number",
|
|
||||||
"enum":[1,2,3],
|
|
||||||
"description": "1 = unobscured shadow, 2 = no shadow, 3 = obscured shadow"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"additionalItems": {
|
|
||||||
"oneOf": [
|
|
||||||
{"$ref":"#/definitions/optionalString"},
|
|
||||||
{"$ref":"#/definitions/inputPrimitive"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"fields": {
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"next": {"$ref":"#/definitions/optionalString"},
|
|
||||||
"topLevel": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"parent": {"$ref":"#/definitions/optionalString"},
|
|
||||||
"shadow": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"x": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"y": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"mutation": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"tagName": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["mutation"]
|
|
||||||
},
|
|
||||||
"children": {
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"proccode": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"argumentids": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"warp": {"$ref":"#/definitions/boolOrBoolString"},
|
|
||||||
"hasnext": {"$ref":"#/definitions/boolOrBoolString"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"opcode"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stage": {
|
|
||||||
"type": "object",
|
|
||||||
"description": "Description of property (and/or property/value pairs) that are unique to the stage.",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["Stage"]
|
|
||||||
},
|
|
||||||
"isStage": {
|
|
||||||
"type": "boolean",
|
|
||||||
"enum": [true]
|
|
||||||
},
|
|
||||||
"tempo": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"videoTransparency": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"videoState": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["on", "off", "on-flipped"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"name",
|
|
||||||
"isStage"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sprite": {
|
|
||||||
"type": "object",
|
|
||||||
"description": "Description of property (and/or property/value pairs) for sprites.",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"not": {"enum": ["Stage", "stage"]}
|
|
||||||
},
|
|
||||||
"isStage": {
|
|
||||||
"type": "boolean",
|
|
||||||
"enum": [false]
|
|
||||||
},
|
|
||||||
"visible": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"x": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"y": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"size": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"direction": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"draggable": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"rotationStyle": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["all around", "don't rotate", "left-right"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"name",
|
|
||||||
"isStage"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"target": {
|
|
||||||
"type": "object",
|
|
||||||
"description" : "Properties common to both Scratch 3.0 Stage and Sprite",
|
|
||||||
"properties": {
|
|
||||||
"currentCostume": {
|
|
||||||
"type": "integer",
|
|
||||||
"minimum": 0
|
|
||||||
},
|
|
||||||
"blocks": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"oneOf": [
|
|
||||||
{"$ref":"#/definitions/block"},
|
|
||||||
{"$ref":"#/definitions/topLevelPrimitive"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variables": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {"$ref":"#/definitions/scalar_variable"}
|
|
||||||
},
|
|
||||||
"lists": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {"$ref":"#/definitions/list"}
|
|
||||||
},
|
|
||||||
"broadcasts": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {"$ref":"#/definitions/broadcast_message"}
|
|
||||||
},
|
|
||||||
"costumes": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {"$ref":"#/definitions/costume"},
|
|
||||||
"minItems": 1,
|
|
||||||
"uniqueItems": true
|
|
||||||
},
|
|
||||||
"sounds": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {"$ref":"#/definitions/sound"},
|
|
||||||
"uniqueItems": true
|
|
||||||
},
|
|
||||||
"volume": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"variables",
|
|
||||||
"costumes",
|
|
||||||
"sounds",
|
|
||||||
"blocks"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"meta": {
|
"meta": {
|
||||||
|
@ -427,21 +23,20 @@
|
||||||
"semver"
|
"semver"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
"targets": {
|
"targets": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{"$ref": "#/definitions/stage" },
|
{"$ref": "sb3_definitions.json#/definitions/stage" },
|
||||||
{"$ref": "#/definitions/target"}
|
{"$ref": "sb3_definitions.json#/definitions/target"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"additionalItems": {
|
"additionalItems": {
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{"$ref": "#/definitions/sprite"},
|
{"$ref": "sb3_definitions.json#/definitions/sprite"},
|
||||||
{"$ref": "#/definitions/target"}
|
{"$ref": "sb3_definitions.json#/definitions/target"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
53
lib/sprite2_schema.json
Normal file
53
lib/sprite2_schema.json
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
{
|
||||||
|
"$id": "https://scratch.mit.edu/sprite2_schema.json",
|
||||||
|
"description": "Scratch 2.0 project schema",
|
||||||
|
"type": "object",
|
||||||
|
"allOf": [
|
||||||
|
{"$ref": "sb2_definitions.json#/definitions/sprite_object"},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"info": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"flashVersion": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"swfVersion": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"userAgent": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"videoOn": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"savedExtensions": {
|
||||||
|
"type": "array",
|
||||||
|
"properties": {
|
||||||
|
"extensionName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"blockSpecs": {
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"menus": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"javascriptURL": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"extensionName",
|
||||||
|
"blockSpecs",
|
||||||
|
"menus",
|
||||||
|
"javascriptURL"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
42
lib/sprite3_schema.json
Normal file
42
lib/sprite3_schema.json
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"$id": "https://scratch.mit.edu/sprite3_schema.json",
|
||||||
|
"$schema": "http://json-schema.org/schema#",
|
||||||
|
"description": "Scratch 3.0 Sprite Schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"meta": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"semver": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^(3.[0-9]+.[0-9]+)$"
|
||||||
|
},
|
||||||
|
"vm": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^([0-9]+.[0-9]+.[0-9]+)($|-)"
|
||||||
|
},
|
||||||
|
"agent": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"semver"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"targets": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"allOf": [
|
||||||
|
{"$ref": "sb3_definitions.json#/definitions/sprite"},
|
||||||
|
{"$ref": "sb3_definitions.json#/definitions/target"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalItems": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"targets"
|
||||||
|
]
|
||||||
|
}
|
|
@ -4,11 +4,13 @@ var unzip = require('./unzip');
|
||||||
* If input a buffer, transforms buffer into a UTF-8 string.
|
* If input a buffer, transforms buffer into a UTF-8 string.
|
||||||
* If input is encoded in zip or gzip format, the input will be extracted and decoded.
|
* If input is encoded in zip or gzip format, the input will be extracted and decoded.
|
||||||
* If input is a string, passes that string along to the given callback.
|
* If input is a string, passes that string along to the given callback.
|
||||||
|
* @param {boolean} isSprite Whether the input should be treated as
|
||||||
|
* a sprite (true) or a whole project (false)
|
||||||
* @param {Buffer | string} input Project data
|
* @param {Buffer | string} input Project data
|
||||||
* @param {Function} callback Error or stringified project data
|
* @param {Function} callback Error or stringified project data
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
module.exports = function (input, callback) {
|
module.exports = function (isSprite, input, callback) {
|
||||||
if (typeof input === 'string') {
|
if (typeof input === 'string') {
|
||||||
// Pass string to callback
|
// Pass string to callback
|
||||||
return callback(null, [input, null]);
|
return callback(null, [input, null]);
|
||||||
|
@ -46,5 +48,5 @@ module.exports = function (input, callback) {
|
||||||
// Return error if legacy encoding detected
|
// Return error if legacy encoding detected
|
||||||
if (isLegacy) return callback('Parser only supports Scratch 2.X and above');
|
if (isLegacy) return callback('Parser only supports Scratch 2.X and above');
|
||||||
|
|
||||||
unzip(input, isGZip, callback);
|
unzip(isSprite, input, isGZip, callback);
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,12 +3,14 @@ var GZip = require('gzip-js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unpacks a zip or gzip file.
|
* Unpacks a zip or gzip file.
|
||||||
|
* @param {boolean} isSprite Whether the input should be treated as
|
||||||
|
* a sprite (true) or whole project (false)
|
||||||
* @param {string} input Zip file provided as a string
|
* @param {string} input Zip file provided as a string
|
||||||
* @param {boolean} isGZip Whether the input is a GZip file, otherwise treat as zip
|
* @param {boolean} isGZip Whether the input is a GZip file, otherwise treat as zip
|
||||||
* @param {array} callback Array including both the project and zip archive
|
* @param {array} callback Array including both the project and zip archive
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
module.exports = function (input, isGZip, callback) {
|
module.exports = function (isSprite, input, isGZip, callback) {
|
||||||
var msg = 'Failed to unzip and extract project.json, with error: ';
|
var msg = 'Failed to unzip and extract project.json, with error: ';
|
||||||
if (isGZip) {
|
if (isGZip) {
|
||||||
var unpackedProject = null;
|
var unpackedProject = null;
|
||||||
|
@ -21,7 +23,7 @@ module.exports = function (input, isGZip, callback) {
|
||||||
}
|
}
|
||||||
return JSZip.loadAsync(input)
|
return JSZip.loadAsync(input)
|
||||||
.then(function (zip) {
|
.then(function (zip) {
|
||||||
return zip.file('project.json').async('string')
|
return zip.file(isSprite ? 'sprite.json' : 'project.json').async('string')
|
||||||
.then(function (project) {
|
.then(function (project) {
|
||||||
return callback(null, [project, zip]);
|
return callback(null, [project, zip]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
var ajv = require('ajv')();
|
var ajv = require('ajv')();
|
||||||
var sb2schema = require('./sb2_schema.json');
|
var sb2Defs = require('./sb2_definitions.json');
|
||||||
var sb3schema = require('./sb3_schema.json');
|
var sb3Defs = require('./sb3_definitions.json');
|
||||||
|
var sb2Schema = require('./sb2_schema.json');
|
||||||
|
var sb3Schema = require('./sb3_schema.json');
|
||||||
|
var sprite2Schema = require('./sprite2_schema.json');
|
||||||
|
var sprite3Schema = require('./sprite3_schema.json');
|
||||||
|
ajv.addSchema(sb2Defs).addSchema(sb3Defs);
|
||||||
|
|
||||||
module.exports = function (input, callback) {
|
module.exports = function (isSprite, input, callback) {
|
||||||
var validateSb2 = ajv.compile(sb2schema);
|
var validateSb2 = ajv.compile(isSprite ? sprite2Schema : sb2Schema);
|
||||||
var validateSb3 = ajv.compile(sb3schema);
|
var validateSb3 = ajv.compile(isSprite ? sprite3Schema : sb3Schema);
|
||||||
|
|
||||||
var isValidSb2 = validateSb2(input);
|
var isValidSb2 = validateSb2(input);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue