janofidel 1.0.0
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/LICENSE.txt +21 -0
- package/README.md +93 -0
- package/bin/jano.js +42 -0
- package/package.json +48 -0
- package/src/dictionary.js +95 -0
- package/src/engine.js +75 -0
- package/src/hook.js +17 -0
- package/src/prelude.js +45 -0
- package/src/runner.js +81 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eyuel Getachew(EyuReaper)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
|
|
2
|
+
---
|
|
3
|
+
# ጃኖ ፊደል (Jano Fidel) 
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
**A Native Amharic Programming Language built on Node.js.**
|
|
7
|
+
|
|
8
|
+
ጃኖ ፊደል (Jano Fidel) is a high-level programming language that allows developers to write full-scale applications using the Ethiopic (Ge'ez) script. It transpiles directly to JavaScript, giving you the power of the Node.js ecosystem with a completely native writing experience.
|
|
9
|
+
|
|
10
|
+
## ✨ ዋና ዋና ባህሪያት (Features)
|
|
11
|
+
|
|
12
|
+
* **Native Keywords**: Use `ይሁን` (let), `ተግባር` (function), and `ከሆነ` (if) instead of English equivalents.
|
|
13
|
+
* **Ethiopic Numerals**: Full support for Ge'ez numbers (፩, ፪, ፲፪...) with a built-in conversion engine.
|
|
14
|
+
* **Amharic Built-ins**: Native aliases for common objects like `ሒሳብ` (Math), `ቀን` (Date), and `ያትም` (console.log).
|
|
15
|
+
* **Asynchronous Support**: Full `ጊዜጠባቂ` (async) and `ጠብቅ` (await) support for modern development.
|
|
16
|
+
* **CLI Tool**: Run your code globally with the `jano` command.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+

|
|
20
|
+
## 🚀 አጀማመር (Quick Start)
|
|
21
|
+
|
|
22
|
+
### 1. Installation
|
|
23
|
+
|
|
24
|
+
Clone the repository and link it to your global path:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cd JanoFidel
|
|
28
|
+
npm install
|
|
29
|
+
sudo npm link
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Writing your first Jano file (`ሰላምታ.jf`)
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
ተግባር ሰላምታ_ስጥ(ስም) {
|
|
37
|
+
መልስ "ሰላም " + ስም + " እንኳን ወደ ጃኖ ፊደል መጣህ!"፤
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
ያትም(ሰላምታ_ስጥ("ዮናስ"))፤
|
|
41
|
+
|
|
42
|
+
// Math with Ge'ez numbers
|
|
43
|
+
ይሁን ውጤት = ፲፪ + ፰፤
|
|
44
|
+
ያትም("፲፪ + ፰ = " + ውጤት)፤
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 3. Running the code
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
jano ሰላምታ.jf
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 📚 የቋንቋው መዝገበ-ቃላት (Dictionary Mapping)
|
|
58
|
+
|
|
59
|
+
| Jano (ጃኖ) | JavaScript Equivalent |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| `ይሁን` | `let` / `var` |
|
|
62
|
+
| `ቋሚ` | `const` |
|
|
63
|
+
| `ተግባር` | `function` |
|
|
64
|
+
| `መደብ` | `class` |
|
|
65
|
+
| `ከሆነ` | `if` |
|
|
66
|
+
| `ካልሆነ` | `else` |
|
|
67
|
+
| `መልስ` | `return` |
|
|
68
|
+
| `ያትም` | `console.log` |
|
|
69
|
+
| `።` | `.` (Dot operator) |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 🛠️ የቴክኒክ መዋቅር (Architecture)
|
|
74
|
+
|
|
75
|
+
1. **Lexer**: Scans `.jf` files for Ethiopic characters and tokens.
|
|
76
|
+
2. **Number Engine**: Converts additive Ethiopic numerals () into Arabic numerals for JavaScript.
|
|
77
|
+
3. **Prelude**: A standard library injected at runtime to provide prototype aliases (e.g., adding `.ርዝመት` to Arrays).
|
|
78
|
+
4. **Transpiler**: Maps the tokens to valid JavaScript and executes via the Node.js VM.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 🤝 ማበረታቻ (Contributing)
|
|
83
|
+
|
|
84
|
+
We welcome contributions! If you want to add more keywords to the `dictionary.js` or expand the `prelude.js` standard library, feel free to open a Pull Request.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 📄 ፈቃድ (License)
|
|
89
|
+
|
|
90
|
+
This project is licensed under the **MIT License**.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
package/bin/jano.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { processFile } = require('../src/engine'); // Assuming processFile handles reading + prelude
|
|
3
|
+
const { runCode } = require('../src/runner');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
// Branding
|
|
7
|
+
const RED_BG = '\x1b[41m';
|
|
8
|
+
const WHITE_TEXT = '\x1b[37m';
|
|
9
|
+
const BOLD = '\x1b[1m';
|
|
10
|
+
const RESET = '\x1b[0m';
|
|
11
|
+
|
|
12
|
+
const logo = `${RED_BG}${WHITE_TEXT}${BOLD} ጃ ${RESET} ${RED_BG}${WHITE_TEXT}${BOLD} ፊ ${RESET} ${BOLD}ጃኖ ፊደል (Jano Fidel)${RESET}\n`;
|
|
13
|
+
|
|
14
|
+
const fileArg = process.argv[2];
|
|
15
|
+
|
|
16
|
+
// 1. Show Help/Logo if no file provided
|
|
17
|
+
if (!fileArg) {
|
|
18
|
+
console.log(logo);
|
|
19
|
+
console.log("አጠቃቀም: jano <ፋይል_ስም.jf>");
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 2. Resolve paths
|
|
24
|
+
const filePath = path.resolve(process.cwd(), fileArg);
|
|
25
|
+
|
|
26
|
+
if (!filePath.endsWith('.jf')) {
|
|
27
|
+
console.error("ስህተት: ፋይሉ በ '.jf' ማለቅ አለበት።");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 3. The Execution Flow
|
|
32
|
+
try {
|
|
33
|
+
// Note: Use your existing processFile which reads the code and adds the prelude
|
|
34
|
+
const jsCode = processFile(filePath);
|
|
35
|
+
|
|
36
|
+
// This calls your professional runner with the styled boxes
|
|
37
|
+
runCode(jsCode, filePath);
|
|
38
|
+
|
|
39
|
+
} catch (err) {
|
|
40
|
+
// This catches high-level file reading errors
|
|
41
|
+
console.error(`\n[የጃኖ ስህተት]: ${err.message}`);
|
|
42
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "janofidel",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Amharic Programming Language (Jano Fidel)",
|
|
5
|
+
"main": "src/engine.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"jano": "bin/jano.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "commonjs",
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=16.0.0"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"test": "mocha test/**/*.test.js"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"amharic",
|
|
21
|
+
"ethiopia",
|
|
22
|
+
"ጃኖ",
|
|
23
|
+
"ፊደል",
|
|
24
|
+
"jano",
|
|
25
|
+
"fidel",
|
|
26
|
+
"language",
|
|
27
|
+
"compiler"
|
|
28
|
+
],
|
|
29
|
+
"author": "EyuReaper",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/EyuReaper/JanoFidel.git"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/EyuReaper/JanoFidel/issues"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/EyuReaper/JanoFidel#readme",
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"mocha": "^11.7.5"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"bin/",
|
|
44
|
+
"src/",
|
|
45
|
+
"README.md",
|
|
46
|
+
"LICENSE.txt"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ጃኖ ፊደል (Jano Fidel) - Official Dictionary
|
|
3
|
+
* Mapping Amharic keywords to JavaScript equivalents.
|
|
4
|
+
* Optimized for DX (Developer Experience) and logical flow.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const JANO_KEYWORDS = {
|
|
8
|
+
// --- Variables & Constants ---
|
|
9
|
+
'ተለዋጭ': 'var', // Added: Traditional variable declaration
|
|
10
|
+
'ይሁን': 'let', // Block-scoped variable
|
|
11
|
+
'ቋሚ': 'const', // Constant
|
|
12
|
+
'ይህ': 'this', // Current context reference
|
|
13
|
+
|
|
14
|
+
// --- Functions & Classes ---
|
|
15
|
+
'ተግባር': 'function',
|
|
16
|
+
'ግንባታ': 'constructor',
|
|
17
|
+
'መልስ': 'return',
|
|
18
|
+
'ተቀባይ' : 'resolve',
|
|
19
|
+
"መደብ": "class",
|
|
20
|
+
'አዲስ': 'new',
|
|
21
|
+
'ያራዝማል': 'extends', // Updated: Logical for inheritance
|
|
22
|
+
'የበላይ': 'super', // Updated: Logical for "the one above"
|
|
23
|
+
'አስገኝ': 'yield', // Updated: Better DX for generators
|
|
24
|
+
'ቃልኪዳን': 'Promise',
|
|
25
|
+
'ቃልኪዳን': 'Promise',
|
|
26
|
+
"ክፍል": "module", // Module
|
|
27
|
+
"ጠይቅ": "require", // Require
|
|
28
|
+
// --- Logic & Flow Control ---
|
|
29
|
+
'ከሆነ': 'if',
|
|
30
|
+
'ካልሆነ': 'else',
|
|
31
|
+
'ምረጥ': 'switch',
|
|
32
|
+
'ሁኔታ': 'case',
|
|
33
|
+
'መደበኛ': 'default',
|
|
34
|
+
'ውጣ': 'break',
|
|
35
|
+
'ቀጥል': 'continue',
|
|
36
|
+
|
|
37
|
+
// --- Loops & Iteration ---
|
|
38
|
+
'ለእያንዳንዱ': 'for',
|
|
39
|
+
'እስከ': 'while',
|
|
40
|
+
'ውስጥ': 'in',
|
|
41
|
+
"የ": "of",
|
|
42
|
+
|
|
43
|
+
// --- Booleans & Types ---
|
|
44
|
+
'እውነት': 'true',
|
|
45
|
+
'ሀሰት': 'false',
|
|
46
|
+
'ባዶ': 'null',
|
|
47
|
+
'አይነት': 'typeof',
|
|
48
|
+
'ምሳሌ': 'instanceof',
|
|
49
|
+
|
|
50
|
+
// --- Exception Handling ---
|
|
51
|
+
'ሞክር': 'try',
|
|
52
|
+
'ያዝ': 'catch',
|
|
53
|
+
'በመጨረሻ': 'finally',
|
|
54
|
+
|
|
55
|
+
// --- Modules & Access Control (Strict/Future Use) ---
|
|
56
|
+
'የጋራ': 'public', // Updated: Intuitive for shared access
|
|
57
|
+
'የግል': 'private', // Hidden/Encapsulated
|
|
58
|
+
'የተጠበቀ': 'protected',
|
|
59
|
+
'ላክ': 'export',
|
|
60
|
+
'ውጤት': 'exports',
|
|
61
|
+
'አምጣ': 'import',
|
|
62
|
+
'ጠብቅ': 'await',
|
|
63
|
+
'መገናኛ': 'interface',
|
|
64
|
+
'ጥቅል': 'package',
|
|
65
|
+
'የማይንቀሳቀስ': 'static',
|
|
66
|
+
'ተከተል': 'enum',
|
|
67
|
+
|
|
68
|
+
// --- Punctuation & Operators ---
|
|
69
|
+
'።': '.', // Updated: Now used as the Dot Operator
|
|
70
|
+
'፤': ';', // Statement terminator
|
|
71
|
+
'፡': ':', // Colon
|
|
72
|
+
'፦': ':', // Preface colon
|
|
73
|
+
'፣': ',', // Comma
|
|
74
|
+
|
|
75
|
+
// --- Math / ሒሳብ ---
|
|
76
|
+
'ሒሳብ': 'Math',
|
|
77
|
+
'ጣራ': 'ceil',
|
|
78
|
+
'ወለል': 'floor',
|
|
79
|
+
'ዘፈቀደ': 'random',
|
|
80
|
+
'ፍጹም': 'abs',
|
|
81
|
+
'ኃይል': 'pow',
|
|
82
|
+
'ሥር': 'sqrt',
|
|
83
|
+
|
|
84
|
+
// --- Numbers ---
|
|
85
|
+
'፟': '0', '፩': '1', '፪': '2', '፫': '3', '፬': '4', '፭': '5',
|
|
86
|
+
'፮': '6', '፯': '7', '፰': '8', '፱': '9', '፲': '10', '፳': '20',
|
|
87
|
+
'፴': '30', '፵': '40', '፶': '50', '፷': '60', '፸': '70', '፹': '80', '፺': '90',
|
|
88
|
+
'፻': '100', '፼': '10000',
|
|
89
|
+
// --- Built-in Utilities ---
|
|
90
|
+
'ያትም': 'console.log',
|
|
91
|
+
'ማንቂያ': 'alert',
|
|
92
|
+
'ጊዜጠባቂ': 'async'
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
module.exports = JANO_KEYWORDS;
|
package/src/engine.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const JANO_KEYWORDS = require('./dictionary');
|
|
2
|
+
const { JANO_PRELUDE } = require('./prelude');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ጃኖ ፊደል (Jano Fidel) Transpiler Engine
|
|
7
|
+
*/
|
|
8
|
+
function transpile(inputCode) {
|
|
9
|
+
// This regex identifies words, strings, and Ethiopic symbols
|
|
10
|
+
const regex = /("[^"]*"|'[^']*'|`[^`]*`|\/\/[^\n]*|[።፤፡፦፣]|[ሀ-፟፩-]+|[a-zA-Z0-9_]+|[^\s])/g;
|
|
11
|
+
|
|
12
|
+
return inputCode.replace(regex, (token) => {
|
|
13
|
+
if (token.startsWith('"') || token.startsWith("'") || token.startsWith("//")) {
|
|
14
|
+
return token;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Check if the token is an Ethiopic Number (e.g., ፲፪)
|
|
18
|
+
if (/^[፩-]+$/.test(token)) {
|
|
19
|
+
return convertEthiopicToArabic(token);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return JANO_KEYWORDS[token] || token;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Simple helper to turn Ethiopic numerals into JavaScript numbers
|
|
27
|
+
function convertEthiopicToArabic(eth) {
|
|
28
|
+
const valueMap = {
|
|
29
|
+
'፩':1, '፪':2, '፫':3, '፬':4, '፭':5, '፮':6, '፯':7, '፰':8, '፱':9,
|
|
30
|
+
'፲':10, '፳':20, '፴':30, '፵':40, '፶':50, '፷':60, '፸':70, '፹':80, '፺':90,
|
|
31
|
+
'፟':0 // Zero, or acts as a separator
|
|
32
|
+
};
|
|
33
|
+
const multiplierMap = {
|
|
34
|
+
'፻': 100,
|
|
35
|
+
'፼': 10000
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
let total = 0;
|
|
39
|
+
let currentBlockValue = 0; // Stores the value of the current digit/tens before a multiplier
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < eth.length; i++) {
|
|
42
|
+
const char = eth[i];
|
|
43
|
+
|
|
44
|
+
if (multiplierMap[char]) {
|
|
45
|
+
// If it's a multiplier (፻ or ፼)
|
|
46
|
+
if (currentBlockValue === 0 && char === '፻') { // Handle cases like just '፻' meaning 100
|
|
47
|
+
currentBlockValue = 1;
|
|
48
|
+
} else if (currentBlockValue === 0 && char === '፼') { // Handle cases like just '፼' meaning 10000
|
|
49
|
+
currentBlockValue = 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
total += currentBlockValue * multiplierMap[char];
|
|
53
|
+
currentBlockValue = 0; // Reset for the next block of numbers
|
|
54
|
+
} else if (valueMap[char] !== undefined) {
|
|
55
|
+
// If it's a digit or ten
|
|
56
|
+
currentBlockValue += valueMap[char];
|
|
57
|
+
} else {
|
|
58
|
+
// Unknown character or invalid numeral sequence
|
|
59
|
+
// For robustness, returning NaN or throwing an error is better
|
|
60
|
+
return NaN;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Add any remaining units/tens that weren't followed by a multiplier
|
|
64
|
+
total += currentBlockValue;
|
|
65
|
+
return total.toString();
|
|
66
|
+
}
|
|
67
|
+
function processFile(filePath) {
|
|
68
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
69
|
+
const transpiled = transpile(content);
|
|
70
|
+
// Combine the prelude (built-ins) with the user's code
|
|
71
|
+
return `(function(){\n${JANO_PRELUDE}\n${transpiled}\n})();`;}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
module.exports = { transpile, processFile, JANO_PRELUDE, convertEthiopicToArabic };
|
package/src/hook.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { transpile, JANO_PRELUDE } = require('./engine');
|
|
3
|
+
|
|
4
|
+
// WARNING: require.extensions is a deprecated API.
|
|
5
|
+
// This usage is temporary and needs to be replaced with a more robust module
|
|
6
|
+
// loading strategy (e.g., Node.js Loader Hooks for ESM or pre-transpilation)
|
|
7
|
+
// in future versions to ensure long-term compatibility and stability with Node.js.
|
|
8
|
+
// Tell Node.js to handle .jf files
|
|
9
|
+
require.extensions['.jf'] = function (module, filename) {
|
|
10
|
+
const content = fs.readFileSync(filename, 'utf8');
|
|
11
|
+
const transpiled = transpile(content);
|
|
12
|
+
|
|
13
|
+
// Inject prelude so the required file also has access to 'ያትም' etc.
|
|
14
|
+
const finalCode = `${JANO_PRELUDE}\n${transpiled}`;
|
|
15
|
+
|
|
16
|
+
module._compile(finalCode, filename);
|
|
17
|
+
};
|
package/src/prelude.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ጃኖ ፊደል (Jano Fidel) - Prelude (Standard Library)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// 1. Node.js safe aliases (only things that exist in Node)
|
|
6
|
+
const ሒሳብ = Math;
|
|
7
|
+
const ጃነማ = JSON;
|
|
8
|
+
const ቀን = Date;
|
|
9
|
+
const ቃልኪዳን = Promise;
|
|
10
|
+
const ያትም = console.log;
|
|
11
|
+
|
|
12
|
+
// 2. Export the template for the transpiler
|
|
13
|
+
// We put 'ማንቂያ' inside the string so it doesn't crash the Node.js process
|
|
14
|
+
const JANO_PRELUDE = `
|
|
15
|
+
const ሒሳብ = Math;
|
|
16
|
+
const ጃነማ = JSON;
|
|
17
|
+
const ቀን = Date;
|
|
18
|
+
const ቃልኪዳን = Promise;
|
|
19
|
+
const ያትም = console.log;
|
|
20
|
+
const ማንቂያ = (typeof alert !== 'undefined') ? alert : console.log;
|
|
21
|
+
|
|
22
|
+
// Global function aliases
|
|
23
|
+
const ቆይ = setTimeout;
|
|
24
|
+
|
|
25
|
+
// Safety Check for Prototypes
|
|
26
|
+
if (!Array.prototype.hasOwnProperty('ርዝመት')) {
|
|
27
|
+
Object.defineProperty(Array.prototype, 'ርዝመት', {
|
|
28
|
+
get: function() { return this.length; },
|
|
29
|
+
configurable: true
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!String.prototype.hasOwnProperty('ርዝመት')) {
|
|
34
|
+
Object.defineProperty(String.prototype, 'ርዝመት', {
|
|
35
|
+
get: function() { return this.length; },
|
|
36
|
+
configurable: true
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!Date.prototype.ወደ_ጽሑፍ) {
|
|
41
|
+
Date.prototype.ወደ_ጽሑፍ = Date.prototype.toDateString;
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
module.exports = { JANO_PRELUDE };
|
package/src/runner.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const { spawn } = require('child_process');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const hookPath = require.resolve('./hook');
|
|
5
|
+
|
|
6
|
+
// --- 1. Helpers (Top of the file) ---
|
|
7
|
+
|
|
8
|
+
const style = {
|
|
9
|
+
red: (t) => `\x1b[31m${t}\x1b[0m`,
|
|
10
|
+
yellow: (t) => `\x1b[33m${t}\x1b[0m`,
|
|
11
|
+
bold: (t) => `\x1b[1m${t}\x1b[0m`,
|
|
12
|
+
reset: '\x1b[0m'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function getExitSummary(code) {
|
|
16
|
+
if (code === 1) return "ያልተጠበቀ ስህተት አጋጥሟል (Uncaught Error)";
|
|
17
|
+
if (code === 130) return "ተጠቃሚው ፕሮግራሙን አቋርጦታል (User Interrupted)";
|
|
18
|
+
return `ፕሮግራሙ በስህተት ተዘግቷል (Exit Code: ${code})`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function remapStack(data, tempFilePath, originalFileName) {
|
|
22
|
+
const output = data.toString();
|
|
23
|
+
const escapedPath = tempFilePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
24
|
+
const regex = new RegExp(escapedPath, 'g');
|
|
25
|
+
return output.replace(regex, originalFileName);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// --- 2. Main Execution Function ---
|
|
29
|
+
|
|
30
|
+
function runCode(jsCode, originalFilePath) {
|
|
31
|
+
const fileName = path.basename(originalFilePath);
|
|
32
|
+
const dirName = path.dirname(path.resolve(originalFilePath));
|
|
33
|
+
const tempFile = path.join(dirName, `.${path.basename(originalFilePath, '.jf')}.tmp.js`);
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
fs.writeFileSync(tempFile, jsCode, 'utf8');
|
|
37
|
+
|
|
38
|
+
// Preload the hook to handle imports
|
|
39
|
+
const hookPath = require.resolve('./hook');
|
|
40
|
+
const child = spawn('node', ['-r', hookPath, tempFile], {
|
|
41
|
+
stdio: ['inherit', 'inherit', 'pipe'],
|
|
42
|
+
cwd: process.cwd()
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
child.stderr.on('data', (data) => {
|
|
46
|
+
const remappedError = remapStack(data, tempFile, fileName);
|
|
47
|
+
process.stderr.write(remappedError);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// --- THE BOX UI LOGIC HERE ---
|
|
51
|
+
child.on('close', (code) => {
|
|
52
|
+
if (fs.existsSync(tempFile)) {
|
|
53
|
+
try { fs.unlinkSync(tempFile); } catch(e) {}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (code !== 0 && code !== null) {
|
|
57
|
+
const summary = getExitSummary(code);
|
|
58
|
+
const border = style.red("┃");
|
|
59
|
+
|
|
60
|
+
console.error(`\n` + style.red("┏" + "━".repeat(60) + "┓"));
|
|
61
|
+
console.error(`${border} ${style.bold(style.red("⚠️ የጃኖ ማጠቃለያ (Jano Summary)"))}`.padEnd(74) + border);
|
|
62
|
+
console.error(style.red("┣" + "━".repeat(60) + "┫"));
|
|
63
|
+
console.error(`${border} ${style.bold("ሁኔታ፦")} ${summary}`.padEnd(68) + border);
|
|
64
|
+
console.error(`${border} ${style.bold("ፋይል፦")} ${fileName}`.padEnd(68) + border);
|
|
65
|
+
console.error(`${border}${' '.repeat(60)}${border}`);
|
|
66
|
+
console.error(`${border} 🔍 ${style.bold("ፍንጭ፦")} የመስመር ቁጥሩን በ ${style.bold(fileName)} ውስጥ ይዩ።`.padEnd(72) + border);
|
|
67
|
+
console.error(style.red("┗" + "━".repeat(60) + "┛") + `\n`);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
process.on('SIGINT', () => {
|
|
72
|
+
if (fs.existsSync(tempFile)) fs.unlinkSync(tempFile);
|
|
73
|
+
process.exit();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
} catch (err) {
|
|
77
|
+
console.error(`\n[የፋይል ስህተት]: ጊዜያዊ ፋይል መፍጠር አልተቻለም፦ ${err.message}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = { runCode };
|