cbs-block 1.0.0 ā 1.0.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.
- package/README.md +55 -0
- package/bin/cbs-block.js +116 -76
- package/index.js +17 -2
- package/myblock.md +13 -0
- package/package.json +11 -3
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# cbs-block SDK š
|
|
2
|
+
|
|
3
|
+
The official toolkit for building **CodeBlock Studio** extensions. Create, package, and share powerful visual blocks with ease.
|
|
4
|
+
|
|
5
|
+
## š¦ Installation
|
|
6
|
+
|
|
7
|
+
Install the CLI globally to use the `cbs-block` command anywhere:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install cbs-block -g
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## š Quick Start
|
|
14
|
+
|
|
15
|
+
### 1. Initialize a Project
|
|
16
|
+
Create a new workspace for your block library:
|
|
17
|
+
```bash
|
|
18
|
+
cbs-block init MyAwesomeBlocks
|
|
19
|
+
cd MyAwesomeBlocks
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Create your First Block
|
|
23
|
+
Generate a template for a new block. Choose a category like `Math`, `Logic`, or `Control`:
|
|
24
|
+
```bash
|
|
25
|
+
cbs-block create SimpleAdd Math
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 3. Build & Package
|
|
29
|
+
When you're ready to share, bundle your blocks into a `.cbspak` file:
|
|
30
|
+
```bash
|
|
31
|
+
cbs-block build
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## š ļø Command Reference
|
|
35
|
+
|
|
36
|
+
| Command | Description |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `init <Name>` | Creates a new block development workspace. |
|
|
39
|
+
| `create <Name> [Category]` | Generates a new `.cbsblock` template. |
|
|
40
|
+
| `list` | Lists all blocks in the current directory. |
|
|
41
|
+
| `lint` | Validates your blocks against the Studio schema. |
|
|
42
|
+
| `build` | Packages your project into a `.cbspak` for the marketplace. |
|
|
43
|
+
| `serve` | Starts a local hot-reload server for real-time testing. |
|
|
44
|
+
| `publish` | Deploys your package to the CBS Marketplace. |
|
|
45
|
+
|
|
46
|
+
## š§© What is a .cbsblock?
|
|
47
|
+
A block is a JSON file that defines its visuals and its logic.
|
|
48
|
+
- **Visuals**: Ports (Input/Output/Flow) and interactive fields.
|
|
49
|
+
- **Logic**: A sandboxed JavaScript function that executes within the Studio.
|
|
50
|
+
|
|
51
|
+
## š The CBS Ecosystem
|
|
52
|
+
Note: `.cbspak` and `.cbsblock` files are proprietary formats optimized for **CodeBlock Studio**. They cannot be opened in standard text editors or other IDEs without the CBS engine.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
**Build the future of visual coding with CodeBlock Studio.**
|
package/bin/cbs-block.js
CHANGED
|
@@ -2,86 +2,126 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const inquirer = require('inquirer');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
const
|
|
9
|
+
async function main() {
|
|
10
|
+
const command = process.argv[2];
|
|
11
|
+
const target = process.argv[3];
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
console.log(chalk.cyan.bold(`\n--- CodeBlock Studio SDK v1.1.0 ---\n`));
|
|
10
14
|
|
|
11
|
-
if (command === 'create'
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
{ name:
|
|
20
|
-
|
|
21
|
-
],
|
|
22
|
-
codeTemplates: {
|
|
23
|
-
python: "print({input1})",
|
|
24
|
-
web: "console.log({input1})"
|
|
25
|
-
},
|
|
26
|
-
logic: "function run(inputs) { return inputs.input1; }"
|
|
27
|
-
};
|
|
15
|
+
if (command === 'create') {
|
|
16
|
+
const answers = await inquirer.prompt([
|
|
17
|
+
{ type: 'input', name: 'name', message: 'Block name:', default: target || 'MyBlock' },
|
|
18
|
+
{ type: 'list', name: 'category', message: 'Category:', choices: ['Math', 'Logic', 'Control', 'Input', 'Output', 'Data', 'Custom'] },
|
|
19
|
+
{ type: 'input', name: 'color', message: 'Hex Color:', default: (a) => {
|
|
20
|
+
const colors = { 'Math': '#4A90E2', 'Logic': '#F5A623', 'Control': '#FFCC00', 'Custom': '#4CAF50' };
|
|
21
|
+
return colors[a.category] || '#4CAF50';
|
|
22
|
+
}},
|
|
23
|
+
{ type: 'confirm', name: 'hasFlow', message: 'Include flow ports?', default: true }
|
|
24
|
+
]);
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
26
|
+
const template = {
|
|
27
|
+
name: answers.name,
|
|
28
|
+
category: answers.category,
|
|
29
|
+
color: answers.color,
|
|
30
|
+
ports: [
|
|
31
|
+
...(answers.hasFlow ? [{ name: "flowIn", type: "FlowIn" }, { name: "flowOut", type: "FlowOut" }] : []),
|
|
32
|
+
{ name: "input1", type: "Input", dataType: "string" },
|
|
33
|
+
{ name: "output1", type: "Output", dataType: "string" }
|
|
34
|
+
],
|
|
35
|
+
codeTemplates: {
|
|
36
|
+
python: "print({input1})",
|
|
37
|
+
web: "console.log({input1})",
|
|
38
|
+
javascript: "console.log({input1})"
|
|
39
|
+
},
|
|
40
|
+
logic: "function run(inputs) { return inputs.input1; }"
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const fileName = `${answers.name.toLowerCase().replace(/\s+/g, '_')}.cbsblock`;
|
|
44
|
+
fs.writeFileSync(fileName, JSON.stringify(template, null, 2));
|
|
45
|
+
console.log(chalk.green(`\nā Successfully created block: ${chalk.bold(fileName)}`));
|
|
46
|
+
|
|
47
|
+
} else if (command === 'init') {
|
|
48
|
+
const answers = await inquirer.prompt([
|
|
49
|
+
{ type: 'input', name: 'projName', message: 'Project Name:', default: target || 'my-block-pack' },
|
|
50
|
+
{ type: 'input', name: 'description', message: 'Description:', default: 'A new CBS block package' }
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
fs.mkdirSync(answers.projName, { recursive: true });
|
|
54
|
+
const pkgPath = path.join(answers.projName, 'package.json');
|
|
55
|
+
fs.writeFileSync(pkgPath, JSON.stringify({
|
|
56
|
+
name: answers.projName,
|
|
57
|
+
version: "1.0.0",
|
|
58
|
+
description: answers.description,
|
|
59
|
+
dependencies: { "cbs-block": "latest" }
|
|
60
|
+
}, null, 2));
|
|
61
|
+
fs.mkdirSync(path.join(answers.projName, 'blocks'), { recursive: true });
|
|
62
|
+
console.log(chalk.green(`\nā Project ${chalk.bold(answers.projName)} initialized!`));
|
|
63
|
+
|
|
64
|
+
} else if (command === 'pack' || command === 'build') {
|
|
65
|
+
const files = fs.readdirSync('.').filter(f => f.endsWith('.cbsblock'));
|
|
66
|
+
const pack = {
|
|
67
|
+
package: path.basename(process.cwd()),
|
|
68
|
+
version: "1.0.0",
|
|
69
|
+
blocks: files.map(f => JSON.parse(fs.readFileSync(f, 'utf8')))
|
|
70
|
+
};
|
|
71
|
+
const packName = `${pack.package}.cbspak`;
|
|
72
|
+
fs.writeFileSync(packName, JSON.stringify(pack, null, 2));
|
|
73
|
+
console.log(chalk.green(`\nā Packed ${files.length} blocks into ${chalk.bold(packName)}`));
|
|
74
|
+
|
|
75
|
+
} else if (command === 'doc' && target) {
|
|
76
|
+
if (!fs.existsSync(target)) return console.error(chalk.red(`Error: File ${target} not found.`));
|
|
77
|
+
const block = JSON.parse(fs.readFileSync(target, 'utf8'));
|
|
78
|
+
const doc = `# Block: ${block.name}\n\n**Category**: ${block.category}\n**Color**: \`${block.color}\`\n\n## Ports\n${block.ports.map(p => `- **${p.name}** (${p.type})`).join('\n')}\n\n## Code Templates\n\`\`\`python\n${block.codeTemplates.python}\n\`\`\``;
|
|
79
|
+
const outName = target.replace('.cbsblock', '.md');
|
|
80
|
+
fs.writeFileSync(outName, doc);
|
|
81
|
+
console.log(chalk.green(`\nā Generated documentation: ${chalk.bold(outName)}`));
|
|
82
|
+
|
|
83
|
+
} else if (command === 'link') {
|
|
84
|
+
const mainAppPath = path.resolve('../../../codebl/blocks');
|
|
85
|
+
if (fs.existsSync(mainAppPath)) {
|
|
86
|
+
const files = fs.readdirSync('.').filter(f => f.endsWith('.cbsblock'));
|
|
87
|
+
files.forEach(f => {
|
|
88
|
+
fs.copyFileSync(f, path.join(mainAppPath, f));
|
|
89
|
+
});
|
|
90
|
+
console.log(chalk.green(`\nā Linked ${files.length} blocks to main app at ${mainAppPath}`));
|
|
91
|
+
} else {
|
|
92
|
+
console.error(chalk.red(`Error: Could not find main app blocks directory at ${mainAppPath}`));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
} else if (command === 'status') {
|
|
96
|
+
console.log(chalk.yellow(`Current Project: ${path.basename(process.cwd())}`));
|
|
97
|
+
const blocks = fs.readdirSync('.').filter(f => f.endsWith('.cbsblock')).length;
|
|
98
|
+
console.log(`Blocks found: ${blocks}`);
|
|
99
|
+
try {
|
|
100
|
+
const qtV = execSync('qmake -v').toString().split('\n')[0];
|
|
101
|
+
console.log(chalk.green(`[PASS] Environment: ${qtV}`));
|
|
102
|
+
} catch {
|
|
103
|
+
console.log(chalk.red(`[FAIL] Qt/qmake not found in PATH`));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
} else if (command === 'lint') {
|
|
107
|
+
const sdk = require('../index.js');
|
|
108
|
+
const files = fs.readdirSync('.').filter(f => f.endsWith('.cbsblock'));
|
|
109
|
+
files.forEach(f => {
|
|
110
|
+
const data = JSON.parse(fs.readFileSync(f, 'utf8'));
|
|
111
|
+
const result = sdk.validate(data);
|
|
112
|
+
if (result.valid) console.log(chalk.green(`${f}: VALID`));
|
|
113
|
+
else console.error(chalk.red(`${f}: INVALID - ${result.error}`));
|
|
114
|
+
});
|
|
54
115
|
} else {
|
|
55
|
-
console.log(
|
|
116
|
+
console.log(chalk.white(`Available commands:`));
|
|
117
|
+
console.log(` ${chalk.bold('create [name]')} - Create a new block interactively`);
|
|
118
|
+
console.log(` ${chalk.bold('init [name]')} - Initialize a new project`);
|
|
119
|
+
console.log(` ${chalk.bold('pack')} - Build a .cbspak package`);
|
|
120
|
+
console.log(` ${chalk.bold('doc <file>')} - Generate markdown documentation`);
|
|
121
|
+
console.log(` ${chalk.bold('link')} - Link blocks to main CodeBlock Studio app`);
|
|
122
|
+
console.log(` ${chalk.bold('lint')} - Validate block definitions`);
|
|
123
|
+
console.log(` ${chalk.bold('status')} - Show SDK & environment status`);
|
|
56
124
|
}
|
|
57
|
-
} else if (command === 'init' && name) {
|
|
58
|
-
fs.mkdirSync(name);
|
|
59
|
-
process.chdir(name);
|
|
60
|
-
fs.writeFileSync('package.json', JSON.stringify({ name, version: "1.0.0", dependencies: { "cbs-block": "latest" } }, null, 2));
|
|
61
|
-
fs.mkdirSync('blocks');
|
|
62
|
-
console.log(`Project ${name} initialized!`);
|
|
63
|
-
} else if (command === 'lint') {
|
|
64
|
-
const sdk = require('../index.js');
|
|
65
|
-
const files = fs.readdirSync('.').filter(f => f.endsWith('.cbsblock'));
|
|
66
|
-
files.forEach(f => {
|
|
67
|
-
const data = JSON.parse(fs.readFileSync(f, 'utf8'));
|
|
68
|
-
if (sdk.validate(data)) console.log(`${f}: VALID`);
|
|
69
|
-
else console.error(`${f}: INVALID (Missing required fields)`);
|
|
70
|
-
});
|
|
71
|
-
} else if (command === 'serve') {
|
|
72
|
-
const http = require('http');
|
|
73
|
-
const server = http.createServer((req, res) => {
|
|
74
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
75
|
-
const blocks = fs.readdirSync('.').filter(f => f.endsWith('.cbsblock'));
|
|
76
|
-
res.end(JSON.stringify(blocks.map(f => JSON.parse(fs.readFileSync(f, 'utf8')))));
|
|
77
|
-
});
|
|
78
|
-
server.listen(8080, () => console.log("Dev server running at http://localhost:8080"));
|
|
79
|
-
} else {
|
|
80
|
-
console.log("Usage:");
|
|
81
|
-
console.log(" cbs-block init <ProjectName>");
|
|
82
|
-
console.log(" cbs-block create <BlockName>");
|
|
83
|
-
console.log(" cbs-block lint");
|
|
84
|
-
console.log(" cbs-block pack");
|
|
85
|
-
console.log(" cbs-block publish");
|
|
86
|
-
console.log(" cbs-block serve");
|
|
87
125
|
}
|
|
126
|
+
|
|
127
|
+
main().catch(err => console.error(chalk.red(`Error: ${err.message}`)));
|
package/index.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
validate: function(block) {
|
|
3
|
-
|
|
3
|
+
const hasRequired = block.name && block.logic && block.codeTemplates && Array.isArray(block.ports);
|
|
4
|
+
if (!hasRequired) return { valid: false, error: "Missing required fields (name, logic, codeTemplates, ports)" };
|
|
5
|
+
|
|
6
|
+
// Color validation
|
|
7
|
+
if (block.color && !/^#[0-9A-F]{6}$/i.test(block.color)) {
|
|
8
|
+
return { valid: false, error: "Invalid hex color format" };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Port validation
|
|
12
|
+
const portNames = new Set();
|
|
13
|
+
for (const p of block.ports) {
|
|
14
|
+
if (portNames.has(p.name)) return { valid: false, error: `Duplicate port name: ${p.name}` };
|
|
15
|
+
portNames.add(p.name);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return { valid: true };
|
|
4
19
|
},
|
|
5
|
-
version: "1.
|
|
20
|
+
version: "1.1.0"
|
|
6
21
|
};
|
package/myblock.md
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cbs-block",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "SDK for creating CodeBlock Studio blocks",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,15 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
11
|
},
|
|
12
|
-
"keywords": [
|
|
12
|
+
"keywords": [
|
|
13
|
+
"cbs",
|
|
14
|
+
"codeblock",
|
|
15
|
+
"visual-programming"
|
|
16
|
+
],
|
|
13
17
|
"author": "CBS Team",
|
|
14
|
-
"license": "MIT"
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"chalk": "^4.1.2",
|
|
21
|
+
"inquirer": "^13.3.2"
|
|
22
|
+
}
|
|
15
23
|
}
|