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 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
- const command = process.argv[2];
7
- const name = process.argv[3];
9
+ async function main() {
10
+ const command = process.argv[2];
11
+ const target = process.argv[3];
8
12
 
9
- const isPack = command === 'pack' || command === 'build';
13
+ console.log(chalk.cyan.bold(`\n--- CodeBlock Studio SDK v1.1.0 ---\n`));
10
14
 
11
- if (command === 'create' && name) {
12
- const category = process.argv[4] || 'Custom';
13
- const colors = { 'Math': '#4A90E2', 'Logic': '#F5A623', 'Control': '#FFCC00', 'Custom': '#4CAF50' };
14
- const template = {
15
- name: name,
16
- category: category,
17
- color: colors[category] || colors['Custom'],
18
- ports: [
19
- { name: "input1", type: "Input", dataType: "string" },
20
- { name: "output1", type: "Output", dataType: "string" }
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
- const fileName = `${name.toLowerCase()}.cbsblock`;
30
- fs.writeFileSync(fileName, JSON.stringify(template, null, 2));
31
- console.log(`Successfully created block: ${fileName}`);
32
- } else if (isPack) {
33
- const files = fs.readdirSync('.').filter(f => f.endsWith('.cbsblock'));
34
- const pack = {
35
- package: path.basename(process.cwd()),
36
- version: "1.0.0",
37
- blocks: files.map(f => JSON.parse(fs.readFileSync(f, 'utf8')))
38
- };
39
- const packName = `${pack.package}.cbspak`;
40
- fs.writeFileSync(packName, JSON.stringify(pack, null, 2));
41
- console.log(`Successfully packed ${files.length} blocks into ${packName}.cbspak`);
42
- } else if (command === 'list') {
43
- const files = fs.readdirSync('.').filter(f => f.endsWith('.cbsblock'));
44
- console.log(`--- Local CBS Blocks (${files.length}) ---`);
45
- files.forEach(f => {
46
- const data = JSON.parse(fs.readFileSync(f));
47
- console.log(`- ${data.name} [${data.category}] (${data.color})`);
48
- });
49
- } else if (command === 'publish') {
50
- const pakFile = fs.readdirSync('.').find(f => f.endsWith('.cbspak'));
51
- if (pakFile) {
52
- console.log(`Uploading ${pakFile} to CBS Marketplace...`);
53
- console.log("Upload Complete! Your extension is now live.");
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("No .cbspak found. Run 'cbs-block pack' first.");
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
- return block.name && block.logic && block.codeTemplates && Array.isArray(block.ports);
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.0.0"
20
+ version: "1.1.0"
6
21
  };
package/myblock.md ADDED
@@ -0,0 +1,13 @@
1
+ # Block: MyBlock
2
+
3
+ **Category**: Custom
4
+ **Color**: `undefined`
5
+
6
+ ## Ports
7
+ - **input1** (Input)
8
+ - **output1** (Output)
9
+
10
+ ## Code Templates
11
+ ```python
12
+ print({input1})
13
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cbs-block",
3
- "version": "1.0.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": ["cbs", "codeblock", "visual-programming"],
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
  }