novac 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 ADDED
File without changes
package/README.md ADDED
File without changes
package/bin/nv+ ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ const { Command } = require('commander');
3
+ const chalk = require('chalk').default;
4
+ const { execSync } = require('child_process');
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ let registery = '@nvplus/'
8
+
9
+ const program = new Command();
10
+
11
+ program
12
+ .name('nv+')
13
+ .description('Nova package manager')
14
+ .version('1.0.0');
15
+
16
+ function publishPackage(tag) {
17
+ try {
18
+ console.log(chalk.cyanBright('📦 Preparing to publish Nova package...'));
19
+
20
+ const pkgPath = fs.existsSync('package.json')
21
+ ? 'package.json'
22
+ : fs.existsSync('nova.json')
23
+ ? 'nova.json'
24
+ : null;
25
+
26
+ if (!pkgPath) {
27
+ console.log(chalk.red('No package.json or nova.json found in this directory.'));
28
+ process.exit(1);
29
+ }
30
+
31
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
32
+ const name = pkg.name || path.basename(process.cwd());
33
+
34
+ if (!name.startsWith(registery)) {
35
+ pkg.name = `${registery}${name}`;
36
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
37
+ }
38
+
39
+ console.log(chalk.green(`🚀 Publishing ${name}@${pkg.version || '0.0.1'} ...`));
40
+ execSync(`npm publish --access public --tag ${tag}`, { stdio: 'inherit' });
41
+
42
+ console.log(chalk.greenBright('✅ Published successfully!'));
43
+ } catch (err) {
44
+ console.error(chalk.red('❌ Publish failed:\n'), err.message);
45
+ }
46
+ }
47
+
48
+ function installPackage(pkg, globalInstall = false) {
49
+ try {
50
+ let scoped = pkg.startsWith(registery) ? pkg : `${registery}${pkg}`;
51
+ console.log(chalk.cyan(`⬇️ Installing ${pkg} ...`));
52
+
53
+ const cmd = globalInstall
54
+ ? `npm install -g ${scoped}`
55
+ : `npm install ${scoped}`;
56
+ execSync(cmd, { stdio: 'inherit' });
57
+
58
+ console.log(chalk.greenBright(`✅ Installed ${pkg} successfully!`));
59
+ } catch (err) {
60
+ console.error(chalk.red('❌ Installation failed:\n'), err.message);
61
+ }
62
+ }
63
+
64
+ // ---- Commands ----
65
+
66
+ program
67
+ .command('publish')
68
+ .description('Publish current Nova package')
69
+ .option('-t, --tag <tag>', 'Optional release tag', 'latest')
70
+ .action((opts) => publishPackage(opts.tag));
71
+
72
+ program
73
+ .command('install <pkg>')
74
+ .description('Install a Nova package')
75
+ .option('-g, --global', 'Install globally', false)
76
+ .action((pkg, opts) => installPackage(pkg, opts.global));
77
+
78
+ // Parse args (Commander auto-handles --help and --version)
79
+ program.parse(process.argv);
80
+
81
+ // If no subcommand is passed, show help
82
+ if (!process.argv.slice(2).length) {
83
+ program.outputHelp();
84
+ }
package/cli.js ADDED
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Nova CLI — built by Wix ⚙️
4
+ * Provides both REPL and file execution support.
5
+ */
6
+
7
+ const { Command } = require("commander");
8
+ const fs = require("fs");
9
+ const path = require("path");
10
+ const readline = require("readline");
11
+
12
+ // Core modules
13
+ const { Parser } = require("./src/core/parser.js");
14
+ const { Executor } = require("./src/core/executor.js");
15
+ let StdLib = require('./src/runtime/stdlib.js');
16
+ const BStd = require('./src/core/bstd.js');
17
+ StdLib = { ...StdLib, ...BStd };
18
+
19
+ // ──────────────────────────────────────────────────────────────
20
+ // Utility helpers
21
+ // ──────────────────────────────────────────────────────────────
22
+ function runCode(source, filename = "<repl>") {
23
+ const parser = new Parser(source);
24
+ const ast = parser.parse();
25
+
26
+ const executor = new Executor(source, StdLib);
27
+ return executor.run(ast);
28
+ }
29
+
30
+ async function startRepl() {
31
+ console.log("Nova REPL — type 'exit' or Ctrl+C to quit\n");
32
+ const rl = readline.createInterface({
33
+ input: process.stdin,
34
+ output: process.stdout,
35
+ prompt: "nova> ",
36
+ });
37
+
38
+ rl.prompt();
39
+ for await (const line of rl) {
40
+ const input = line.trim();
41
+ if (input === ".exit" || input === ".quit") break;
42
+ if (!input) {
43
+ rl.prompt();
44
+ continue;
45
+ }
46
+
47
+ try {
48
+ const executor = new Executor(line, StdLib);
49
+ const parser = new Parser(input);
50
+ const ast = parser.parse();
51
+ const result = executor.run(ast);
52
+ if (result !== undefined) console.log(executor.stringify(result));
53
+ } catch (err) {
54
+ console.error('Error: ', err);
55
+ }
56
+
57
+ rl.prompt();
58
+ }
59
+
60
+ rl.close();
61
+ }
62
+
63
+ // ──────────────────────────────────────────────────────────────
64
+ // CLI definition
65
+ // ──────────────────────────────────────────────────────────────
66
+ const program = new Command();
67
+
68
+ program
69
+ .name("nova")
70
+ .description("The Nova language CLI — run, build, and explore your code.")
71
+ .version("1.0.0");
72
+
73
+ program
74
+ .argument("[file]", "Nova source file to execute")
75
+ .option("-r, --repl", "Start interactive REPL mode")
76
+ .action(async (file, options) => {
77
+ if (options.repl || !file) {
78
+ await startRepl();
79
+ return;
80
+ }
81
+
82
+ const filepath = path.resolve(process.cwd(), file);
83
+ if (!fs.existsSync(filepath)) {
84
+ console.error(`Error: file not found: ${filepath}`);
85
+ process.exit(1);
86
+ }
87
+
88
+ const source = fs.readFileSync(filepath, "utf8");
89
+ try {
90
+ runCode(source, filepath);
91
+ } catch (err) {
92
+ console.error(`RuntimeError: ${err.message}`);
93
+ process.exit(1);
94
+ }
95
+ });
96
+
97
+ program.parse(process.argv);
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "novac",
3
+ "version": "1.0.0",
4
+ "description": "a rewrite version of my package nvlang",
5
+ "license": "MIT",
6
+ "author": "purcwix",
7
+ "type": "commonjs",
8
+ "main": "cli.js",
9
+ "bin": {
10
+ "nv+": "bin/nv+"
11
+ },
12
+ "directories": {
13
+ "example": "examples",
14
+ "test": "tests"
15
+ },
16
+ "scripts": {
17
+ "test": "echo \"Error: no test specified\" && exit 1"
18
+ },
19
+ "dependencies": {
20
+ "chalk": "^5.6.2",
21
+ "commander": "^14.0.1"
22
+ },
23
+ "devDependencies": {}
24
+ }
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ const pkgPath = path.join(__dirname, '..', 'package.json');
6
+ const binDir = path.join(__dirname, '..', 'bin');
7
+
8
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
9
+ pkg.bin = pkg.bin || {};
10
+
11
+ if (fs.existsSync(binDir)) {
12
+ const files = fs.readdirSync(binDir);
13
+ for (const file of files) {
14
+ const fullPath = `./bin/${file}`;
15
+ const name = path.parse(file).name;
16
+ pkg.bin[name] = fullPath;
17
+ }
18
+ }
19
+
20
+ // sort keys (optional, just for tidiness)
21
+ pkg.bin = Object.fromEntries(Object.entries(pkg.bin).sort(([a], [b]) => a.localeCompare(b)));
22
+
23
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
24
+ console.log('✅ package.json bin field updated automatically.');
@@ -0,0 +1,14 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ let Air = {};
5
+
6
+ // read all .js files in the current directory
7
+ fs.readdirSync(__dirname)
8
+ .filter(file => file !== 'bstd.js' && file.endsWith('.js'))
9
+ .forEach(file => {
10
+ const name = path.basename(file, '.js');
11
+ Air[name] = require(path.join(__dirname, file));
12
+ });
13
+
14
+ module.exports = { Air };
@@ -0,0 +1,187 @@
1
+ /**
2
+ * describe.js
3
+ * Converts Nova Air AST into natural-language explanations.
4
+ * Style: clear, rhythmic, and human — with natural punctuation.
5
+ */
6
+
7
+ function describe(node, depth = 0) {
8
+ const indent = " ".repeat(depth);
9
+ if (!node) return "";
10
+ if (Array.isArray(node))
11
+ return node.map(n => describe(n, depth)).join("\n");
12
+
13
+ switch (node.kind) {
14
+ // ─────────── ROOT ───────────
15
+ case "program":
16
+ return node.nodes.map(n => describe(n, depth)).join("\n");
17
+
18
+ // ─────────── DECLARATION ───────────
19
+ case "declare": {
20
+ const kind = node.isConst ? "constant" : "variable";
21
+ const pointer = node.isPointer ? "pointer to " : "";
22
+ if (node.destructure)
23
+ return `${indent}Create a ${kind} pattern: unpack into { ${node.destructure.props
24
+ .map(p => p.alias)
25
+ .join(", ")} }${node.value ? `, using ${describe(node.value)}` : ""}.`;
26
+ if (node.value)
27
+ return `${indent}Declare ${kind}: ${pointer}${node.name}, and set it to ${describe(node.value)}.`;
28
+ return `${indent}Declare ${kind}: ${pointer}${node.name}.`;
29
+ }
30
+
31
+ // ─────────── ASSIGNMENT ───────────
32
+ case "assign":
33
+ return `${indent}Set ${describe(node.name)} to ${describe(node.value)}.`;
34
+
35
+ // ─────────── REFERENCES ───────────
36
+ case "ref":
37
+ return node.name;
38
+
39
+ // ─────────── VALUES ───────────
40
+ case "value":
41
+ return JSON.stringify(node.value);
42
+
43
+ // ─────────── FUNCTIONS ───────────
44
+ case "function": {
45
+ const args = node.args.length
46
+ ? node.args.map(a => describe(a)).join(", ")
47
+ : "no arguments";
48
+ return `${indent}${node.isAsync ? "Async " : ""}function '${node.name}': takes (${args}), and ${summarizeBody(node.body)}.`;
49
+ }
50
+
51
+ case "arrowfunc": {
52
+ const args = node.args.length
53
+ ? node.args.map(a => describe(a)).join(", ")
54
+ : "no arguments";
55
+ return `${indent}Arrow function: takes (${args}), and ${summarizeBody(node.body)}.`;
56
+ }
57
+
58
+ // ─────────── RETURN ───────────
59
+ case "return":
60
+ return `${indent}Return ${node.value ? describe(node.value) : "nothing"}${node.terminate ? ", immediately" : ""}.`;
61
+
62
+ // ─────────── CLASS ───────────
63
+ case "class":
64
+ return `${indent}Define a class '${node.name}'${node.superClass ? `, extending ${describe(node.superClass)}` : ""}: \n${node.members
65
+ .map(m => describe(m, depth + 1))
66
+ .join("\n")}`;
67
+
68
+ // ─────────── BRANCHING ───────────
69
+ case "branch": {
70
+ const base = `${indent}${capitalize(node.type)} statement: ${
71
+ node.args ? `when (${describe(node.args)})` : ""
72
+ }, then:\n${describe(node.body, depth + 1)}`;
73
+ const next = node.next
74
+ ? `\n${indent}else:\n${describe(node.next.body, depth + 1)}`
75
+ : "";
76
+ return base + next;
77
+ }
78
+
79
+ // ─────────── LOOPS ───────────
80
+ case "while":
81
+ case "repeat":
82
+ case "for":
83
+ case "do":
84
+ case "until":
85
+ return `${indent}${capitalize(node.kind)} loop: ${
86
+ node.args ? `condition is ${describe(node.args)},` : ""
87
+ } running:\n${describe(node.body, depth + 1)}`;
88
+
89
+ // ─────────── CALLS ───────────
90
+ case "call": {
91
+ const name = typeof node.name === "string" ? node.name : describe(node.name);
92
+ const args = node.args.length
93
+ ? `, with arguments: ${node.args.map(a => describe(a)).join(", ")}`
94
+ : "";
95
+ return `${indent}Call ${name}${args}.`;
96
+ }
97
+
98
+ // ─────────── PROPERTY ACCESS ───────────
99
+ case "prop":
100
+ return `${describe(node.object)}.${node.name}`;
101
+
102
+ // ─────────── INDEX ACCESS ───────────
103
+ case "subscript":
104
+ return `${describe(node.object)}[${describe(node.index)}]`;
105
+
106
+ // ─────────── ASYNC / AWAIT ───────────
107
+ case "await":
108
+ return `${indent}Await: wait for ${describe(node.operand)} to complete.`;
109
+
110
+ // ─────────── ERROR HANDLING ───────────
111
+ case "throw":
112
+ return `${indent}Throw ${describe(node.value)}.`;
113
+
114
+ case "try":
115
+ return `${indent}Try block:\n${describe(node.tryBody, depth + 1)}${
116
+ node.catchBody
117
+ ? `\n${indent}If an error occurs: catch it as '${node.catchName}', then:\n${describe(node.catchBody, depth + 1)}`
118
+ : ""
119
+ }${node.finallyBody ? `\n${indent}Finally: always run\n${describe(node.finallyBody, depth + 1)}` : ""}`;
120
+
121
+ // ─────────── EXPRESSIONS ───────────
122
+ case "binary":
123
+ return `${describe(node.left)} ${node.operator} ${describe(node.right)}.`;
124
+
125
+ case "unary":
126
+ return `${node.operator}${describe(node.operand)}.`;
127
+
128
+ case "postfix":
129
+ return `${describe(node.operand)}${node.operator}.`;
130
+
131
+ // ─────────── MEMORY / POINTERS ───────────
132
+ case "deref":
133
+ return `the value pointed to by ${describe(node.operand)}.`;
134
+
135
+ case "currency":
136
+ return `${describe(node.operand)} (in ${node.name}).`;
137
+
138
+ // ─────────── STRUCTURES ───────────
139
+ case "object":
140
+ return `object: { ${Object.entries(node.props)
141
+ .map(([k, v]) => `${k}: ${describe(v)}`)
142
+ .join(", ")} }.`;
143
+
144
+ case "array":
145
+ return `array: [${node.elements.map(e => describe(e)).join(", ")}].`;
146
+
147
+ // ─────────── PATTERNS ───────────
148
+ case "objpattern":
149
+ return `{ ${node.props
150
+ .map(p => `${p.key}${p.key !== p.alias ? ` as ${p.alias}` : ""}`)
151
+ .join(", ")} }`;
152
+
153
+ case "arrpattern":
154
+ return `[${node.elements.map(e => describe(e)).join(", ")}]`;
155
+
156
+ // ─────────── TEMPLATES ───────────
157
+ case "template":
158
+ return node.parts.map(p => describe(p)).join("");
159
+
160
+ // ─────────── EXECUTION ───────────
161
+ case "exec":
162
+ return `${indent}Execute: ${describe(node.expr)}.`;
163
+
164
+ // ─────────── FALLBACK ───────────
165
+ case "EOF":
166
+ return "";
167
+ default:
168
+ return `${indent}(Unknown node type: '${node.kind}')`;
169
+ }
170
+ }
171
+
172
+ // ─────────── HELPERS ───────────
173
+ function summarizeBody(body) {
174
+ if (!body || !body.length) return "does nothing";
175
+ const first = describe(body[0]);
176
+ if (body.length === 1) {
177
+ if (first.startsWith("Return")) return `returns ${first.replace(/^Return /, "").trim()}`;
178
+ return `does: ${first.toLowerCase()}`;
179
+ }
180
+ return "runs several steps in order";
181
+ }
182
+
183
+ function capitalize(str) {
184
+ return str.charAt(0).toUpperCase() + str.slice(1);
185
+ }
186
+
187
+ module.exports = { describe };