Comparing version 0.0.1-prealpha.1 to 0.0.1-prealpha.2
{ | ||
"name": "sb-util", | ||
"version": "0.0.1-prealpha.1", | ||
"version": "0.0.1-prealpha.2", | ||
"description": "Scratch blocks utilities: open and query Scratch blocks formats", | ||
@@ -9,4 +9,8 @@ "repository": "https://github.com/bocoup/sb-util", | ||
"build": "tsc", | ||
"test": "jest" | ||
"jest": "jest", | ||
"lint": "eslint \"src/**/*.ts\"", | ||
"prettier": "prettier \"src/**/*.ts\"", | ||
"test": "npm run prettier -- --check && npm run lint && npm run jest" | ||
}, | ||
"main": "dist/sb-util.js", | ||
"keywords": [ | ||
@@ -41,10 +45,20 @@ "scratch", | ||
"license": "BSD-3-Clause", | ||
"dependencies": {}, | ||
"devDependencies": {}, | ||
"workspaces": [ | ||
"packages/*" | ||
], | ||
"files": [ | ||
"dist" | ||
] | ||
"dependencies": { | ||
"isomorphic-fetch": "^2.2.1", | ||
"jszip": "^3.2.2" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^24.0.15", | ||
"@types/node": "^12.6.3", | ||
"@typescript-eslint/eslint-plugin": "^1.13.0", | ||
"@typescript-eslint/parser": "^1.13.0", | ||
"eslint": "^6.1.0", | ||
"eslint-config-prettier": "^6.0.0", | ||
"eslint-plugin-prettier": "^3.1.0", | ||
"jest": "^24.8.0", | ||
"lerna": "^3.15.0", | ||
"prettier": "^1.18.2", | ||
"ts-jest": "^24.0.2", | ||
"typescript": "^3.5.3" | ||
} | ||
} |
377
README.md
@@ -0,10 +1,371 @@ | ||
# sb-util | ||
**sb-util** is a utility that allows developers to query a Scratch Project for collections of sprites, blocks, assets, and any other information within a *.sb3 file's project.json. | ||
This repo holds the TypeScript implementation of sb-util, which can be imported as a JavaScript library or used as a CLI. | ||
## Table of Contents | ||
- [sb-util Proposal (RFC)](https://github.com/bocoup/sb-util/blob/master/README.md#sb-util-proposal-rfc) | ||
- [JavaScript API Proposal](https://github.com/bocoup/sb-util/blob/master/README.md#javascript-api-proposal) | ||
- [CLI Proposal](https://github.com/bocoup/sb-util/blob/master/README.md#cli-proposal) | ||
- [Development](https://github.com/bocoup/sb-util/blob/master/README.md#development) | ||
# Development | ||
--- | ||
## sb-util Proposal (RFC) | ||
We, at Bocoup, propose **sb-util**, a JavaScript and CLI utility that allows developers to query a Scratch Project for collections of sprites, blocks, assets, and project metadata. | ||
sb-util will accomplish this by consuming **.sb3** files generated by Scratch. **.sb3** files are used to save and load projects, and within an **.sb3** file there is a **project.json**, which is the JSON representation of the entities within a Scratch project. sb-util will provide an API that allows developers to query the project.json for project information. | ||
The resulting tool should be usable in test suites, scripts, and applications. | ||
## Javascript API Proposal | ||
- [Loading a Scratch Project](https://github.com/bocoup/sb-util#javascript-api-proposal) | ||
- [ScratchProject](https://github.com/bocoup/sb-util#scratchproject) | ||
- [SpriteCollection](https://github.com/bocoup/sb-util#spritecollection) | ||
- [Sprite](https://github.com/bocoup/sb-util#sprite) | ||
- [BlockCollection](https://github.com/bocoup/sb-util#blockcollection) | ||
- [Block](https://github.com/bocoup/sb-util#block) | ||
- [AssetCollection](https://github.com/bocoup/sb-util#assetcollection) | ||
- [Asset](https://github.com/bocoup/sb-util#asset) | ||
API methods that have been implmented are marked with *implemented*. | ||
### **Loading a Scratch Project** - *implemented* | ||
sb-util exposes loading functions to asynchronously instantiate a **ScratchProject** | ||
object. These loading functions handle file I/O and HTTP request handling, decoupling that process from the ScratchProject object itself. | ||
--- | ||
**loadSb3(*sb3File*)** | ||
Parameter(s): *sb3File*. String representing local file location of an *.sb3 file or a URI to an *.sb3 file | ||
Return: *Promise*. This Promise object will resolve to a ScratchProject | ||
``` | ||
const sp = await loadSb3('foo.sb3'); | ||
``` | ||
**loadProjectJson(*projectJsonFile*)** | ||
Parameter(s): *projectJsonFile*. String representing local file location of an project.json file or a URI to an project.json file | ||
Return: *Promise*. This Promise object will resolve to a ScratchProject | ||
``` | ||
const sp = await loadProjectJson('project.json'); | ||
``` | ||
**loadCloudId(*cloudId*)** | ||
Parameter(s): *cloudId*. Number representing a Cloud ID in Scratch | ||
Return: *Promise*. This Promise object will resolve to a ScratchProject | ||
``` | ||
const sp = await loadCloudId(123456); | ||
``` | ||
--- | ||
### ScratchProject | ||
**ScratchProject(*projectJSON*)** - *implemented* | ||
A *ScratchProject* gets initialized by an object, represented by the project.json. The *assetFetcher* is an optional constructor argument that represents an object is responsible for retrieving asset buffers for an Asset object. | ||
``` | ||
const { ScratchProject } - require('sb-util'); | ||
// Use the above loading methods or directly instantiate: | ||
const sp = new ScratchProject(projectJson); | ||
``` | ||
**Methods** | ||
**assets()** | ||
Return: *AssetCollection* representing all the assets of a project | ||
``` | ||
let assets = sp.assets() | ||
``` | ||
**blocks()** -- *implemented* | ||
Return: *BlockCollection* representing all the blocks in the project. This *BlockCollection* can be further filtered to get specific blocks | ||
``` | ||
let blocks = sp.blocks(); | ||
``` | ||
**sprites(...args)** - *implemented* | ||
Return: *SpriteCollection* representing all sprites in the project. A selector syntax can be passed to this function to get sprites that meet the syntax criteria | ||
``` | ||
let sprites = sp.sprites(); | ||
let stage = sp.sprites('[isStage=true]').pop(); | ||
let sprite1 = sp.sprites('[name="Cat"]').pop(); | ||
``` | ||
**stage()** - *implemented* | ||
Return: *Sprite* a stage | ||
``` | ||
let stage = sp.stage(); | ||
``` | ||
**variables()** | ||
Return: a list of *Variable* objects in the project | ||
``` | ||
let vars = sp.variables(); | ||
``` | ||
--- | ||
### SpriteCollection | ||
A *SpriteCollection* represents an iterable collection of objects that represent Sprites. Array methods such as *map()*, *filter()*, and *pop()* are available. | ||
**Methods** | ||
**first()** - *implemented* | ||
Return: the first element in the SpriteCollection, null if the collection is empty | ||
**prop(attribute)** - *implemented* | ||
Parameter: *attribute* string. | ||
Return: the value of the given attribute for the **first** element in the SpriteCollection, undefined if the prop does not exist, null if the SpriteCollection is empty | ||
Attributes available to pass: *name, isStage, variables, lists, broadcasts, blocks, comments, currentCostume, costumes, sounds, volume, layerOrder, temp, videoTransparency, videoState, textToSpeechLanguage, visible, x, y, size, direction, draggable, rotationStyle* | ||
**query(selector)** - *implemented* | ||
Parameter(s): *selector* string in the CSS selector syntax style. | ||
Return: *SpriteCollection* | ||
``` | ||
let stage = sp.sprites('[isStage=true]'); | ||
let sprite1 = sp.sprites('[name="Cat"]'); | ||
``` | ||
Possible selector syntax, in attribute selector style: | ||
| Sprite Attribute | Selector Syntax | | ||
| ---------------- |------------------------------------------------------------------| | ||
| isStage | [isStage={true or false}] | | ||
| layerOrder | [layerOrder={a number}] | | ||
| draggable | [draggable={true or false}] | | ||
| rotationStyle | [rotationStyle={"all around" or "left-right" or "don't rotate"}] | | ||
--- | ||
### Sprite | ||
A *Sprite* is a singleton of *SpriteCollection*, with additional methods that are specific to a single Sprite. A Sprite can be a stage or an individual sprite. | ||
**Methods** | ||
**prop(attribute)** - *implemented* | ||
Parameter: *attribute* string. | ||
Return: *any* value for a given attribute | ||
``` | ||
const currentCostume = sprite.prop('currentCostume'); | ||
``` | ||
Attributes available to pass: *name, isStage, variables, lists, broadcasts, blocks, comments, currentCostume, costumes, sounds, volume, layerOrder, temp, videoTransparency, videoState, textToSpeechLanguage, visible, x, y, size, direction, draggable, rotationStyle* | ||
**blocks()** - *implemented* | ||
Return: *BlockCollection* | ||
``` | ||
const sprite = sp.sprites('[name="Cat"]'); | ||
const blocks = sprite.blocks(); | ||
``` | ||
**assets()** | ||
Return: *AssetCollection* | ||
``` | ||
const assets = sprite.assets(); | ||
``` | ||
**position()** - *implemented* | ||
Return: the (X, Y) cooredinates of a Sprite in Object notation | ||
``` | ||
const { x, y } = sprite.position(); | ||
``` | ||
**broadcasts()** - *implemented* | ||
Return: a list of Objects representing a broadcast, which contains an id and a message | ||
``` | ||
const broadcasts = sprite.broadcasts(); | ||
// A mapping example | ||
Object.entries(broadcasts).map(([key, value]) => ({ messageId: key, message: value })); | ||
``` | ||
**lists()** - *implemented* | ||
Return: a list of Objects representing a list, which contains an id, name, and an Array of values | ||
``` | ||
const lists = sprite.lists(); | ||
Object.entries(lists).map(([key, value]) => console.log({key, listName: value[0], values: value[1]})); | ||
``` | ||
--- | ||
### BlockCollection | ||
A *BlockCollection* represents and iterable collection of objects that represent Blocks. Array methods such as *map()*, *filter()*, and *pop()* are available. | ||
**Methods** | ||
**first()** - *implemented* | ||
Return: the first element in the BlockCollection, null if the collection is empty | ||
**query(selector)** - *partially implemented* | ||
Parameter(s): *selector*, a string with the convention similar to CSS selector syntax | ||
Return: *BlockCollection* | ||
This is a mapping of Block object attributes to selector syntax: | ||
| Block Attribute | CSS-like Selector Syntax | Status | | ||
| --------------------|-------------------------------|--------| | ||
| opcode ([Full set of opcodes](https://github.com/LLK/scratch-vm/tree/develop/src/blocks )) | Type selector. `blocks.query('event_whenflagclicked')` or `blocks.query('control_if_else')`| implemented | | ||
| block type ([Full set of block types](https://en.scratch-wiki.info/wiki/Blocks#List_of_Blocks)) | Class selector. `blocks.query('.motion')` or `blocks.query('.sensing')` | implemented | | ||
| block shape ([Full set of block shapes](https://en.scratch-wiki.info/wiki/Blocks#Block_Shapes))| Pseudo class selector. `blocks.query(':hat')` or `blocks.query(':reporter')` | not implemented | | ||
The selector syntax can be combined for more fine-grained filtering. | ||
**Get all motion reporter blocks** | ||
``` | ||
const motionReporterBlocks = blocks.query('.motion :reporter'); | ||
``` | ||
**renderToText()** | ||
Return: a text representation of blocks that are connected. The output will be a consumable JSON format, which can be written to a file and also be converted to YAML | ||
``` | ||
const sprite1Blocks = sp.sprites({name: 'Sprite1'}).blocks(); | ||
const blockTextRepresentation = sprite1Blocks.renderToText() | ||
// Output | ||
{ | ||
"blockGroups" : [ | ||
// First group of blocks | ||
{ | ||
"output": [ | ||
"event_whenflagclicked", | ||
{ | ||
"control_if_else" : { | ||
"if": { | ||
"condition" : { | ||
"sensing_keypressed": { | ||
"sensing_keyoptions": "space" | ||
} | ||
} | ||
}, | ||
"then": [ | ||
{ | ||
"data_changevariableby": { | ||
"variable": "my variable", | ||
"value": 10 | ||
} | ||
}, | ||
{ | ||
"motion_gotoxy": { | ||
"X": "my variable", | ||
"Y": 10 | ||
} | ||
} | ||
], | ||
"else": [ | ||
{ | ||
"control_wait_until": { | ||
"sensing_keypressed": { | ||
"sensing_keyoptions": "space" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
} | ||
] | ||
}, | ||
// Second group of blocks | ||
{ | ||
"output": { ... } | ||
} | ||
] | ||
} | ||
``` | ||
--- | ||
### Block | ||
A *Block* is a singleton of *BlockCollection*. It has additional methods, specific to the data held by an individual block. | ||
**Methods** | ||
**prop(attribute)** - *implemented* | ||
Parameter: *attribute* string. | ||
Return: *any* value for a given attribute | ||
Attributes available to pass: *opcode, next, parent, inputs, fields, shadow, topLevel* | ||
**args(selector)** | ||
This method is similar to *query*. *args* returns the inputs or fields (depending on the query string) of a block using one of the strings defined below. Certain query strings can return an input or a field. | ||
A sample of selector values for the *args* method is defined in this table: | ||
| Inputs | Fields | Both Input and Field | | ||
|------------------------------|-----------------------------|------------------------| | ||
| X, Y, DURATION, MESSAGE, SECS CONDITION, SUBSTACK, OPERAND, TIMES, CHANGE, FROM, VALUE, BROADCAST_INPUT, BACKDROP, VOLUME, NUM1, NUM2 | EFFECT, BROADCAST_OPTION, VARIABLE, STOP_OPTION | COSTUME, TOUCHINGOBJECTMENU, TO, SOUND_MENU | | ||
``` | ||
const condition = block.args('CONDITION'); | ||
const variable = block.args('VARIABLE'); | ||
const operand = block.args('OPERAND'); | ||
``` | ||
**substacks()** | ||
Returns the substacks for the block as an list of Objects representing a substack. If a block is not capable of having a substack, the list will be empty. | ||
--- | ||
### AssetCollection | ||
An *AssetCollection* represents an interable collection of objects that represent Assets, which are static files included in an *.sb3 file or somwhere the user designates, used for costumes and sounds. | ||
**Methods** | ||
**query(selector)** | ||
Parameter(s): A string in the CSS selector style | ||
Return: *AssetCollection* | ||
Possible selector syntax: | ||
| Asset Attribute | Selector Syntax | | ||
|-----------------|-----------------| | ||
| name | Attribute selector. `assets.query('name="83a9787d4cb6f3b7632b4ddfebf74367.wav")`| | ||
| dataFormat | Type Selector. `assets.query('wav')`| | ||
--- | ||
### Asset | ||
An *Asset* is a singleton of *AssetCollection*. | ||
**Methods** | ||
**toBuffer()** | ||
Return: *Promise* to the file buffer of this Asset | ||
## CLI Proposal | ||
*Coming soon* | ||
--- | ||
## Development | ||
sb-util is implemented in TypeScript and will be available as a JavaScript library on [npm](https://www.npmjs.com/package/sb-util) and as a CLI tool. | ||
## Install Dependencies | ||
``` | ||
npm install | ||
``` | ||
## Build | ||
``` | ||
yarn build | ||
npm run build | ||
``` | ||
@@ -14,3 +375,9 @@ | ||
``` | ||
yarn test | ||
npm test | ||
``` | ||
## Linting Code | ||
This project uses [https://prettier.io](Prettier) to format code and [https://eslint.org/](ESLint) for linting (catching errors). To format and lint, run | ||
``` | ||
npm run lint | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
190985
35
1723
383
2
12
+ Addedisomorphic-fetch@^2.2.1
+ Addedjszip@^3.2.2
+ Addedcore-util-is@1.0.3(transitive)
+ Addedencoding@0.1.13(transitive)
+ Addediconv-lite@0.6.3(transitive)
+ Addedimmediate@3.0.6(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedis-stream@1.1.0(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedisomorphic-fetch@2.2.1(transitive)
+ Addedjszip@3.10.1(transitive)
+ Addedlie@3.3.0(transitive)
+ Addednode-fetch@1.7.3(transitive)
+ Addedpako@1.0.11(transitive)
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
+ Addedsetimmediate@1.0.5(transitive)
+ Addedstring_decoder@1.1.1(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
+ Addedwhatwg-fetch@3.6.20(transitive)