cajyu 0.0.0-stage → 1.0.1

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 CHANGED
@@ -1,3 +1,166 @@
1
- # Temporary Holding Version
1
+ # Cajyu
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **A clean, practical programming language that transpiles to JavaScript.**
4
+
5
+ Cajyu gives you a simpler, more expressive syntax while staying fully compatible with the JavaScript ecosystem.
6
+
7
+ [![npm](https://img.shields.io/badge/npm-cajyu-blue)](https://www.npmjs.com/package/cajyu)
8
+ [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
9
+ [![Version](https://img.shields.io/badge/version-1.1.0-brightgreen)](package.json)
10
+
11
+ ---
12
+
13
+ ## Features
14
+
15
+ - Clean syntax for variables, functions, classes, loops and conditionals
16
+ - Transpiles to modern JavaScript
17
+ - Real HTTP server with POST handlers, sleep/wake
18
+ - Official libraries: `serial`, `fs`, `math`, `http`, `websocket`
19
+ - Optional runtime typing
20
+ - Async with `sync fn` and `wait`
21
+ - One-liners and stacking
22
+ - CLI with flags and multiple commands
23
+
24
+ ---
25
+
26
+ ## Quick Start
27
+
28
+ ```bash
29
+ # After publishing
30
+ npm install -g cajyu
31
+
32
+ # Or from source
33
+ node bin/cajyu.js --help
34
+ ```
35
+
36
+ ```bash
37
+ cajyu init
38
+ cajyu inst serial
39
+ cajyu inst http
40
+ cajyu run examples/fatorial.cjy
41
+ ```
42
+
43
+ ---
44
+
45
+ ## CLI
46
+
47
+ ```
48
+ cajyu [flags]
49
+ cajyu <command> [options]
50
+ ```
51
+
52
+ | Command | Description |
53
+ |------------------|--------------------------------------|
54
+ | `init` | Create a new project |
55
+ | `inst <lib>` | Install a library from CajyuLibs |
56
+ | `run <file.cjy>` | Compile and run a file |
57
+ | `list` | List installed libraries |
58
+ | `update` | Update libraries (planned) |
59
+
60
+ | Flag | Description |
61
+ |------------------|----------------------|
62
+ | `-h, --help` | Show help |
63
+ | `-v, --version` | Show version |
64
+
65
+ ---
66
+
67
+ ## Syntax
68
+
69
+ ### Variables
70
+ ```cajyu
71
+ var name = "Cajyu"
72
+ var age:Number = 17
73
+ ```
74
+
75
+ ### Functions
76
+ ```cajyu
77
+ fn add a, b {
78
+ return a + b
79
+ }
80
+ ```
81
+
82
+ ### Control flow & loops
83
+ ```cajyu
84
+ if x > 10 {
85
+ print("big")
86
+ } elif x > 5 {
87
+ print("medium")
88
+ } else {
89
+ print("small")
90
+ }
91
+
92
+ for i in range(10) {
93
+ print(i)
94
+ }
95
+ ```
96
+
97
+ ### Classes
98
+ ```cajyu
99
+ class Person {
100
+ Main name, age {
101
+ Self.name = name
102
+ Self.age = age
103
+ }
104
+ greet {
105
+ return "Hello, " + Self.name
106
+ }
107
+ }
108
+ ```
109
+
110
+ ### HTTP
111
+ ```cajyu
112
+ import Server from CajyuLibs.http
113
+
114
+ var server = new Server(3000)
115
+
116
+ server.post(fn b {
117
+ if !b.a and !b.b {
118
+ return { code: 400 }
119
+ }
120
+ return { code: 200, result: b.a + b.b }
121
+ })
122
+ ```
123
+
124
+ ### WebSocket
125
+ ```cajyu
126
+ import WS from CajyuLibs.websocket
127
+
128
+ var wss = new WS.Server(8080)
129
+ wss.on("connection", fn client {
130
+ print("client connected")
131
+ })
132
+ wss.on("message", fn msg, client {
133
+ wss.broadcast(msg)
134
+ })
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Libraries
140
+
141
+ Official libraries: https://github.com/abs-js/CajyuLibs
142
+
143
+ ```bash
144
+ cajyu inst serial
145
+ cajyu inst fs
146
+ cajyu inst math
147
+ cajyu inst http
148
+ cajyu inst websocket
149
+ ```
150
+
151
+ ---
152
+
153
+ ## Contributing
154
+
155
+ Pull requests are welcome. Priority areas:
156
+
157
+ - A proper parser (current one is regex-based)
158
+ - More language features
159
+ - Additional libraries
160
+ - Better error messages
161
+
162
+ ---
163
+
164
+ ## License
165
+
166
+ MIT
package/bin/cajyu.js ADDED
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { execSync } from 'child_process';
6
+ import { compileAndRun } from '../src/compiler.js';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ const CAJYULIBS_REPO = 'https://github.com/abs-js/CajyuLibs.git';
12
+ const VERSION = '1.1.0';
13
+
14
+ const args = process.argv.slice(2);
15
+ const command = args[0];
16
+ const flags = args.filter(a => a.startsWith('-'));
17
+
18
+ function hasFlag(...names) {
19
+ return names.some(n => flags.includes(n) || flags.includes(`-${n}`) || flags.includes(`--${n}`));
20
+ }
21
+
22
+ async function main() {
23
+ if (hasFlag('v', 'version', '--version')) {
24
+ console.log(`Cajyu ${VERSION}`);
25
+ return;
26
+ }
27
+
28
+ if (hasFlag('h', 'help', '--help') || !command) {
29
+ showHelp();
30
+ return;
31
+ }
32
+
33
+ if (command === 'init') {
34
+ initProject();
35
+ } else if (command === 'inst' || command === 'install') {
36
+ const libName = args[1];
37
+ if (!libName || libName.startsWith('-')) {
38
+ console.error('Usage: cajyu inst <library>');
39
+ process.exit(1);
40
+ }
41
+ await installLib(libName);
42
+ } else if (command === 'run') {
43
+ const file = args.find(a => a.endsWith('.cjy') || (a !== 'run' && !a.startsWith('-')));
44
+ if (!file) {
45
+ console.error('Usage: cajyu run <file.cjy>');
46
+ process.exit(1);
47
+ }
48
+ await compileAndRun(file);
49
+ } else if (command === 'list') {
50
+ listInstalled();
51
+ } else if (command === 'update') {
52
+ console.log('Updating is not yet implemented. Re-run `cajyu inst <lib>` after deleting the folder.');
53
+ } else {
54
+ console.error(`Unknown command: ${command}`);
55
+ showHelp();
56
+ process.exit(1);
57
+ }
58
+ }
59
+
60
+ function showHelp() {
61
+ console.log(`
62
+ Cajyu ${VERSION} — a custom programming language that transpiles to JavaScript
63
+
64
+ Usage:
65
+ cajyu [flags]
66
+ cajyu <command> [options]
67
+
68
+ Commands:
69
+ init Create a new Cajyu project
70
+ inst <lib> Install a library from CajyuLibs
71
+ run <file.cjy> Compile and execute a Cajyu file
72
+ list List installed libraries
73
+ update Update installed libraries (coming soon)
74
+
75
+ Flags:
76
+ -h, --help Show this help
77
+ -v, --version Show version
78
+
79
+ Examples:
80
+ cajyu init
81
+ cajyu inst http
82
+ cajyu inst websocket
83
+ cajyu run examples/fatorial.cjy
84
+ cajyu list
85
+ `);
86
+ }
87
+
88
+ function initProject() {
89
+ const pkg = {
90
+ name: "cajyu-project",
91
+ version: "1.0.0",
92
+ description: "Cajyu project",
93
+ main: "index.cjy",
94
+ type: "module"
95
+ };
96
+ fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
97
+ if (!fs.existsSync('CajyuLibs')) fs.mkdirSync('CajyuLibs');
98
+ console.log('Cajyu project initialized.');
99
+ }
100
+
101
+ async function installLib(libName) {
102
+ console.log(`Installing "${libName}" from CajyuLibs...`);
103
+
104
+ const targetDir = path.join(process.cwd(), 'CajyuLibs', libName);
105
+ if (fs.existsSync(targetDir)) {
106
+ console.log(`Library "${libName}" already installed.`);
107
+ return;
108
+ }
109
+
110
+ const tmpDir = path.join('/tmp', `cajyulibs-${Date.now()}`);
111
+ try {
112
+ console.log('Cloning CajyuLibs repository...');
113
+ execSync(`git clone --depth 1 ${CAJYULIBS_REPO} ${tmpDir}`, { stdio: 'inherit' });
114
+
115
+ const sourceLib = path.join(tmpDir, libName);
116
+ if (!fs.existsSync(sourceLib)) {
117
+ console.error(`Library "${libName}" not found in CajyuLibs.`);
118
+ process.exit(1);
119
+ }
120
+
121
+ fs.mkdirSync(path.dirname(targetDir), { recursive: true });
122
+ fs.cpSync(sourceLib, targetDir, { recursive: true });
123
+
124
+ const pkgPath = path.join(targetDir, 'package.json');
125
+ if (fs.existsSync(pkgPath)) {
126
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
127
+ if (pkg.dependencies && Object.keys(pkg.dependencies).length > 0) {
128
+ console.log('Installing library dependencies...');
129
+ execSync('npm install', { cwd: targetDir, stdio: 'inherit' });
130
+ }
131
+ }
132
+
133
+ console.log(`✓ Library "${libName}" installed to CajyuLibs/${libName}/`);
134
+ } catch (err) {
135
+ console.error('Failed to install library:', err.message);
136
+ process.exit(1);
137
+ } finally {
138
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
139
+ }
140
+ }
141
+
142
+ function listInstalled() {
143
+ const libsDir = path.join(process.cwd(), 'CajyuLibs');
144
+ if (!fs.existsSync(libsDir)) {
145
+ console.log('No libraries installed yet.');
146
+ return;
147
+ }
148
+ const libs = fs.readdirSync(libsDir).filter(d => fs.statSync(path.join(libsDir, d)).isDirectory());
149
+ if (libs.length === 0) {
150
+ console.log('No libraries installed.');
151
+ } else {
152
+ console.log('Installed libraries:');
153
+ libs.forEach(l => console.log(` - ${l}`));
154
+ }
155
+ }
156
+
157
+ main().catch(console.error);
@@ -0,0 +1,16 @@
1
+ import print from CajyuLibs.serial
2
+
3
+ class Pessoa {
4
+ Main nome, idade {
5
+ Self.nome = nome
6
+ Self.idade = idade
7
+ }
8
+ // private nome
9
+ // private idade
10
+ apresentar {
11
+ return "Oi, eu sou " + Self.nome + " e tenho " + Self.idade + " anos"
12
+ }
13
+ }
14
+
15
+ var p = new Pessoa("Ana", 17)
16
+ print(p.apresentar())
@@ -0,0 +1,13 @@
1
+ import print from CajyuLibs.serial
2
+
3
+ fn fac a {
4
+ if a <= 1 {
5
+ return 1
6
+ } else {
7
+ return a * fac(a - 1)
8
+ }
9
+ }
10
+
11
+ for i in range(10) {
12
+ print(fac(i));
13
+ }
@@ -0,0 +1,18 @@
1
+ import Server from CajyuLibs.http
2
+ import print from CajyuLibs.serial
3
+
4
+ var server = new Server(3000)
5
+ print("Servidor Cajyu pronto na porta 3000")
6
+
7
+ server.post(fn b {
8
+ if !b.a and !b.b {
9
+ return { code: 400 }
10
+ }
11
+ return {
12
+ code: 200,
13
+ result: b.a + b.b
14
+ }
15
+ })
16
+
17
+ print("POST / com JSON {a, b} para somar")
18
+ print("server.sleep() e server.wake() disponíveis")
package/package.json CHANGED
@@ -1,6 +1,17 @@
1
1
  {
2
2
  "name": "cajyu",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.01",
4
+ "description": "Cajyu programming language - a custom language that compiles to JavaScript",
5
+ "main": "src/compiler.js",
6
+ "bin": {
7
+ "cajyu": "./bin/cajyu.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node bin/cajyu.js"
11
+ },
12
+ "keywords": ["cajyu", "compiler", "language", "javascript"],
13
+ "author": "Cajyu Team",
14
+ "license": "MIT",
15
+ "dependencies": {},
16
+ "type": "module"
17
+ }
@@ -0,0 +1,149 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { pathToFileURL } from 'url';
4
+
5
+ export async function compileAndRun(filePath) {
6
+ if (!fs.existsSync(filePath)) {
7
+ console.error(`Arquivo não encontrado: ${filePath}`);
8
+ process.exit(1);
9
+ }
10
+ const source = fs.readFileSync(filePath, 'utf-8');
11
+ const jsCode = transpile(source, path.dirname(filePath));
12
+ const tempFile = path.join('/tmp', `cajyu_${Date.now()}.mjs`);
13
+ fs.writeFileSync(tempFile, jsCode);
14
+ try {
15
+ await import(pathToFileURL(tempFile).href);
16
+ console.log('--- Execução Cajyu ---');
17
+ } catch (err) {
18
+ console.error('Erro na execução:', err.message);
19
+ console.error(err.stack);
20
+ } finally {
21
+ try { fs.unlinkSync(tempFile); } catch {}
22
+ }
23
+ }
24
+
25
+ function transpile(source, baseDir) {
26
+ const lines = source.split('\n');
27
+ const imports = [];
28
+ const codeLines = [];
29
+ for (const line of lines) {
30
+ const m = line.match(/^\s*import\s+(\*|\w+)\s+from\s+['"]?([^\s'"]+)['"]?\s*;?\s*$/);
31
+ if (m) imports.push({ what: m[1], from: m[2] });
32
+ else codeLines.push(line);
33
+ }
34
+ let code = codeLines.join('\n');
35
+
36
+ let importCode = '';
37
+ for (const imp of imports) {
38
+ const libPath = resolveLib(imp.from, baseDir);
39
+ if (libPath && fs.existsSync(libPath)) {
40
+ const url = pathToFileURL(libPath).href;
41
+ if (imp.what === '*') {
42
+ importCode += `const _lib = await import('${url}'); Object.assign(globalThis, _lib.CayjuLib || _lib);\n`;
43
+ } else {
44
+ importCode += `const { CayjuLib: _lib${imp.what} } = await import('${url}'); const ${imp.what} = _lib${imp.what}.${imp.what} || _lib${imp.what};\n`;
45
+ }
46
+ }
47
+ }
48
+
49
+ code = preprocessKeywords(code);
50
+ code = transpileFunctions(code);
51
+ code = transpileAnonymousFunctions(code);
52
+ code = transpileControlFlow(code);
53
+ code = transpileOneLiners(code);
54
+
55
+ const builtins = `
56
+ function _range(a, b, c) {
57
+ const r = [];
58
+ if (b == null) for (let i = 1; i <= a; i++) r.push(i);
59
+ else if (c == null) for (let i = a; i <= b; i++) r.push(i);
60
+ else for (let i = a; i <= b; i += c) r.push(i);
61
+ return r;
62
+ }
63
+ function _typeCheck(val, type) {
64
+ if (!type) return val;
65
+ const t = String(type).toLowerCase();
66
+ if (t === 'string' && typeof val !== 'string') throw new Error('esperado String');
67
+ if ((t === 'number' || t === 'int' || t === 'float') && typeof val !== 'number') throw new Error('esperado Number');
68
+ if (t === 'boolean' && typeof val !== 'boolean') throw new Error('esperado Boolean');
69
+ if (t === 'array' && !Array.isArray(val)) throw new Error('esperado Array');
70
+ return val;
71
+ }
72
+ `;
73
+
74
+ const final = `
75
+ ${importCode}
76
+ ${builtins}
77
+ (async () => {
78
+ ${code}
79
+ })().catch(console.error);
80
+ `;
81
+
82
+ fs.writeFileSync('/tmp/cajyu_debug.mjs', final);
83
+ return final;
84
+ }
85
+
86
+ function resolveLib(from, baseDir) {
87
+ if (from.startsWith('CajyuLibs')) {
88
+ const name = from.split('.')[1] || 'serial';
89
+ const cands = [
90
+ path.resolve(baseDir, 'CajyuLibs', name, 'main.js'),
91
+ path.resolve(baseDir, '..', 'CajyuLibs', name, 'main.js'),
92
+ path.resolve(process.cwd(), 'CajyuLibs', name, 'main.js'),
93
+ ];
94
+ return cands.find(p => fs.existsSync(p));
95
+ }
96
+ return path.resolve(baseDir, from);
97
+ }
98
+
99
+ function cleanParams(s) {
100
+ return (s || '').trim().split(',').map(p => p.trim().split(':')[0].trim()).filter(Boolean).join(', ');
101
+ }
102
+
103
+ function preprocessKeywords(code) {
104
+ return code
105
+ .replace(/\band\b/g, '&&')
106
+ .replace(/\bor\b/g, '||')
107
+ .replace(/\bnot\b/g, '!')
108
+ .replace(/sync\s+fn\s+(\w+)/g, 'async function $1')
109
+ .replace(/\bwait\s+/g, 'await ')
110
+ .replace(/\belif\b/g, 'else if')
111
+ .replace(/\bSelf\./g, 'this.')
112
+ .replace(/\brange\(/g, '_range(')
113
+ .replace(/\/\/\s*private\s+(\w+)/g, '/* private $1 */')
114
+ .replace(/var\s+(\w+):(\w+)\s*=\s*(.+)/g, 'let $1 = _typeCheck($3, "$2")')
115
+ .replace(/var\s+(\w+)\s*=/g, 'let $1 =');
116
+ }
117
+
118
+ function transpileFunctions(code) {
119
+ return code
120
+ .replace(/^fn\s+(\w+)\s+([^{]*)\{/gm, (_, n, p) => `function ${n}(${cleanParams(p)}) {`)
121
+ .replace(/^fn\s+(\w+)\s*\{/gm, 'function $1() {')
122
+ .replace(/Main\s+([^{]*)\{/g, (_, p) => `constructor(${cleanParams(p)}) {`)
123
+ .replace(/^\s*(\w+)\s*\{/gm, (m, name) => {
124
+ const keywords = ['if','else','while','for','return','class','fn','function','constructor'];
125
+ if (keywords.includes(name)) return m;
126
+ return ` ${name}() {`;
127
+ });
128
+ }
129
+
130
+ function transpileAnonymousFunctions(code) {
131
+ return code.replace(/(?<!^|\n)fn\s+([^{]*)\{/g, (_, params) => {
132
+ const p = cleanParams(params);
133
+ return `function(${p}) {`;
134
+ });
135
+ }
136
+
137
+ function transpileControlFlow(code) {
138
+ return code
139
+ .replace(/if\s+([^{]+?)\s*\{/g, 'if ($1) {')
140
+ .replace(/else\s+if\s+([^{]+?)\s*\{/g, 'else if ($1) {')
141
+ .replace(/while\s+([^{]+?)\s*\{/g, 'while ($1) {')
142
+ .replace(/for\s+(\w+)\s+in\s+([^ {\n]+)(\s*\{)/g, 'for (let $1 of $2) $3');
143
+ }
144
+
145
+ function transpileOneLiners(code) {
146
+ return code
147
+ .replace(/return\s+(\{[^}]*\}|.+?)\s+if\s+([^;]+);/g, 'if ($2) return $1;')
148
+ .replace(/if\s+([^:{;\n]+)\s+return\s+([^;\n{]+)/g, 'if ($1) return $2;');
149
+ }