purus 0.1.0 → 0.2.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-ja.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Logo](https://raw.githubusercontent.com/otoneko1102/purus/refs/heads/main/logo.png)](https://purus.work)
4
4
 
5
- [English](https://raw.githubusercontent.com/otoneko1102/purus/refs/heads/main/README.md) | **日本語**
5
+ [English](https://github.com/otoneko1102/purus#readme) | **日本語**
6
6
 
7
7
  </div>
8
8
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Logo](https://raw.githubusercontent.com/otoneko1102/purus/refs/heads/main/logo.png)](https://purus.work)
4
4
 
5
- **English** | [日本語](https://raw.githubusercontent.com/otoneko1102/purus/refs/heads/main/README-ja.md)
5
+ **English** | [日本語](https://github.com/otoneko1102/purus/blob/main/README-ja.md)
6
6
 
7
7
  </div>
8
8
 
@@ -55,4 +55,4 @@ otoneko. https://github.com/otoneko1102
55
55
 
56
56
  ## License
57
57
 
58
- Distributed under the Apache 2.0 License. See [LICENSE](https://raw.githubusercontent.com/otoneko1102/purus/refs/heads/main/LICENSE) for more information.
58
+ Distributed under the Apache 2.0 License. See [LICENSE](https://github.com/otoneko1102/purus/blob/main/LICENSE) for more information.
package/bin/purus.js CHANGED
@@ -1,3 +1,52 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- require("../lib/purus-compiler.js");
3
+
4
+ const VERSION = require("../package.json").version;
5
+ const cmd = process.argv[2];
6
+
7
+ function printHelp() {
8
+ console.log(`purus v${VERSION} - A language that compiles to JavaScript`);
9
+ console.log("");
10
+ console.log("Usage:");
11
+ console.log(" purus build [file] Compile to JavaScript");
12
+ console.log(" purus build --directory <dir> Compile all files in directory");
13
+ console.log(" purus build --output <dir> Specify output directory");
14
+ console.log(" purus build Compile using config.purus");
15
+ console.log(" .purus -> .js");
16
+ console.log(" .cpurus -> .cjs (CommonJS)");
17
+ console.log(" .mpurus -> .mjs (ES Module)");
18
+ console.log(" purus build --no-header [file] Compile without header comment");
19
+ console.log(" purus run [file] Run without generating files");
20
+ console.log(" purus run --directory <dir> Run all files in directory");
21
+ console.log(" purus run Run using config.purus");
22
+ console.log(" purus check <file> Syntax check only");
23
+ console.log(" purus new [name] [-y] Create a new project");
24
+ console.log(" purus init Initialize project in current directory");
25
+ console.log(" purus version Show version");
26
+ console.log(" purus help Show this help");
27
+ console.log("");
28
+ console.log("Aliases: compile = build, create = new");
29
+ }
30
+
31
+ switch (cmd) {
32
+ case "new":
33
+ case "create":
34
+ require("../lib/create.js");
35
+ break;
36
+ case "build":
37
+ case "compile":
38
+ require("../lib/build-wrapper.js");
39
+ break;
40
+ case "run":
41
+ require("../lib/run-wrapper.js");
42
+ break;
43
+ case "help":
44
+ case "--help":
45
+ case "-h":
46
+ case undefined:
47
+ printHelp();
48
+ break;
49
+ default:
50
+ require("../lib/purus-compiler.js");
51
+ break;
52
+ }
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const { loadConfig } = require("./config.js");
6
+ const { compile } = require("./purus-core.js");
7
+
8
+ const args = process.argv.slice(3);
9
+
10
+ let file = null;
11
+ let directory = null;
12
+ let output = null;
13
+ let noHeader = false;
14
+ let toStdout = false;
15
+
16
+ for (let i = 0; i < args.length; i++) {
17
+ if (args[i] === "--no-header") {
18
+ noHeader = true;
19
+ } else if (args[i] === "--stdout") {
20
+ toStdout = true;
21
+ } else if (args[i] === "--directory" || args[i] === "-d") {
22
+ directory = args[++i];
23
+ } else if (args[i] === "--output" || args[i] === "-o") {
24
+ output = args[++i];
25
+ } else if (!args[i].startsWith("-")) {
26
+ file = args[i];
27
+ }
28
+ }
29
+
30
+ if (file) {
31
+ // Single file - delegate to MoonBit compiler
32
+ require("./purus-compiler.js");
33
+ } else {
34
+ let entryDir;
35
+ let outputDir;
36
+ let useHeader;
37
+
38
+ if (directory) {
39
+ entryDir = path.resolve(directory);
40
+ outputDir = output ? path.resolve(output) : path.resolve("dist");
41
+ useHeader = !noHeader;
42
+
43
+ const result = loadConfig();
44
+ if (result) {
45
+ if (!output) {
46
+ outputDir = path.resolve(
47
+ result.configDir,
48
+ result.config.output || "dist"
49
+ );
50
+ }
51
+ useHeader = result.config.header !== false && !noHeader;
52
+ }
53
+ } else {
54
+ const result = loadConfig();
55
+ if (!result) {
56
+ console.log("Error: no input file specified and no config.purus found");
57
+ console.log("");
58
+ console.log("Usage:");
59
+ console.log(" purus build <file> Compile a single file");
60
+ console.log(
61
+ " purus build --directory <dir> Compile all files in directory"
62
+ );
63
+ console.log(
64
+ " purus build Compile using config.purus"
65
+ );
66
+ process.exit(1);
67
+ }
68
+
69
+ const { config, configDir } = result;
70
+ entryDir = path.resolve(configDir, config.entry || "src");
71
+ outputDir = output
72
+ ? path.resolve(output)
73
+ : path.resolve(configDir, config.output || "dist");
74
+ useHeader = config.header !== false && !noHeader;
75
+ }
76
+
77
+ if (!fs.existsSync(entryDir)) {
78
+ console.log(`Error: entry directory '${entryDir}' not found`);
79
+ process.exit(1);
80
+ }
81
+
82
+ const stat = fs.statSync(entryDir);
83
+ let files;
84
+
85
+ if (stat.isFile()) {
86
+ files = [entryDir];
87
+ // For single file entry, output is a file too
88
+ if (!fs.existsSync(path.dirname(outputDir))) {
89
+ fs.mkdirSync(path.dirname(outputDir), { recursive: true });
90
+ }
91
+ } else {
92
+ files = findPurusFiles(entryDir);
93
+ }
94
+
95
+ if (files.length === 0) {
96
+ console.log(`No .purus files found in ${entryDir}`);
97
+ process.exit(0);
98
+ }
99
+
100
+ let count = 0;
101
+ for (const f of files) {
102
+ const source = fs.readFileSync(f, "utf8");
103
+ const js = compile(source, { header: useHeader });
104
+ let outputPath;
105
+
106
+ if (stat.isFile()) {
107
+ outputPath = outputDir;
108
+ } else {
109
+ outputPath = getOutputPath(f, entryDir, outputDir);
110
+ }
111
+
112
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
113
+ fs.writeFileSync(outputPath, js);
114
+ console.log(
115
+ `Compiled ${path.relative(process.cwd(), f)} -> ${path.relative(process.cwd(), outputPath)}`
116
+ );
117
+ count++;
118
+ }
119
+ console.log(`\n${count} file${count === 1 ? "" : "s"} compiled.`);
120
+ }
121
+
122
+ function findPurusFiles(dir) {
123
+ const results = [];
124
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
125
+ const fullPath = path.join(dir, entry.name);
126
+ if (entry.isDirectory()) {
127
+ results.push(...findPurusFiles(fullPath));
128
+ } else if (/\.(c|m)?purus$/.test(entry.name)) {
129
+ results.push(fullPath);
130
+ }
131
+ }
132
+ return results;
133
+ }
134
+
135
+ function getOutputPath(inputFile, inputBase, outputBase) {
136
+ const relative = path.relative(inputBase, inputFile);
137
+ let ext = ".js";
138
+ if (inputFile.endsWith(".cpurus")) ext = ".cjs";
139
+ else if (inputFile.endsWith(".mpurus")) ext = ".mjs";
140
+ const base = relative.replace(/\.(c|m)?purus$/, "");
141
+ return path.join(outputBase, base + ext);
142
+ }
package/lib/config.js ADDED
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+
6
+ function parseConfig(configPath) {
7
+ const content = fs.readFileSync(configPath, "utf8");
8
+ const config = {};
9
+
10
+ for (const line of content.split("\n")) {
11
+ const trimmed = line.trim();
12
+ if (trimmed === "" || trimmed.startsWith("--")) continue;
13
+
14
+ const match = trimmed.match(/^const\s+([\w.-]+)\s+be\s+(.+)$/);
15
+ if (!match) continue;
16
+
17
+ const key = match[1];
18
+ let value = match[2].trim();
19
+
20
+ if (value.startsWith("///") && value.endsWith("///")) {
21
+ value = value.slice(3, -3);
22
+ } else if (value === "true") {
23
+ value = true;
24
+ } else if (value === "false") {
25
+ value = false;
26
+ } else if (/^\d+$/.test(value)) {
27
+ value = parseInt(value, 10);
28
+ } else if (/^\d+\.\d+$/.test(value)) {
29
+ value = parseFloat(value);
30
+ }
31
+
32
+ const keys = key.split(".");
33
+ let target = config;
34
+ for (let i = 0; i < keys.length - 1; i++) {
35
+ if (!target[keys[i]] || typeof target[keys[i]] !== "object") {
36
+ target[keys[i]] = {};
37
+ }
38
+ target = target[keys[i]];
39
+ }
40
+ target[keys[keys.length - 1]] = value;
41
+ }
42
+
43
+ return config;
44
+ }
45
+
46
+ function findConfig(startDir) {
47
+ let dir = startDir || process.cwd();
48
+ while (true) {
49
+ const configPath = path.join(dir, "config.purus");
50
+ if (fs.existsSync(configPath)) return configPath;
51
+ const parent = path.dirname(dir);
52
+ if (parent === dir) return null;
53
+ dir = parent;
54
+ }
55
+ }
56
+
57
+ function loadConfig(startDir) {
58
+ const configPath = findConfig(startDir);
59
+ if (!configPath) return null;
60
+ return {
61
+ config: parseConfig(configPath),
62
+ configPath,
63
+ configDir: path.dirname(configPath),
64
+ };
65
+ }
66
+
67
+ module.exports = { parseConfig, findConfig, loadConfig };
package/lib/create.js ADDED
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const readline = require("readline");
6
+ const { spawnSync } = require("child_process");
7
+
8
+ function question(rl, text) {
9
+ return new Promise((resolve) => rl.question(text, (a) => resolve(a.trim())));
10
+ }
11
+
12
+ function isDirEmpty(dir) {
13
+ return fs.readdirSync(dir).length === 0;
14
+ }
15
+
16
+ async function run() {
17
+ const args = process.argv.slice(3);
18
+ const yesFlag = args.includes("-y") || args.includes("--yes");
19
+ const positionalArgs = args.filter((a) => !a.startsWith("-"));
20
+
21
+ let projectName = positionalArgs[0] || "";
22
+
23
+ const rl = readline.createInterface({
24
+ input: process.stdin,
25
+ output: process.stdout,
26
+ });
27
+
28
+ try {
29
+ if (!projectName) {
30
+ projectName = await question(rl, "Project name: ");
31
+ if (!projectName) {
32
+ console.log("Error: project name required");
33
+ process.exit(1);
34
+ }
35
+ }
36
+
37
+ const projectDir = path.resolve(projectName);
38
+
39
+ if (fs.existsSync(projectDir) && !isDirEmpty(projectDir)) {
40
+ console.log(`Error: directory '${projectName}' already exists and is not empty`);
41
+ process.exit(1);
42
+ }
43
+
44
+ console.log(`\nCreating project in ./${projectName}...`);
45
+ fs.mkdirSync(path.join(projectDir, "src"), { recursive: true });
46
+
47
+ // config.purus
48
+ const configPurus = `-- Purus Configuration
49
+
50
+ const entry be ///src///
51
+ const output be ///dist///
52
+ const header be true
53
+
54
+ -- Linter settings
55
+ const lint.no-var be ///warn///
56
+ const lint.indent-size be 2
57
+ const lint.max-line-length be ///off///
58
+ `;
59
+ fs.writeFileSync(path.join(projectDir, "config.purus"), configPurus);
60
+
61
+ // .prettierrc
62
+ const prettierrc =
63
+ JSON.stringify(
64
+ {
65
+ tabWidth: 2,
66
+ semi: false,
67
+ plugins: ["@puruslang/prettier-plugin-purus"],
68
+ },
69
+ null,
70
+ 2
71
+ ) + "\n";
72
+ fs.writeFileSync(path.join(projectDir, ".prettierrc"), prettierrc);
73
+
74
+ // src/main.purus
75
+ const mainPurus = `-- main.purus
76
+
77
+ const message be ///Hello, World///
78
+ console.log[message]
79
+ `;
80
+ fs.writeFileSync(path.join(projectDir, "src/main.purus"), mainPurus);
81
+
82
+ // README.md
83
+ const readme = `# ${projectName}
84
+
85
+ A [Purus](https://purus.work) project.
86
+
87
+ ## Getting Started
88
+
89
+ \`\`\`sh
90
+ npm install
91
+ purus build
92
+ \`\`\`
93
+
94
+ ## Scripts
95
+
96
+ | Script | Description |
97
+ |---|---|
98
+ | \`npm run build\` | Compile Purus to JavaScript |
99
+ | \`npm run exec\` | Run without compiling to files |
100
+ | \`npm run format\` | Format with Prettier |
101
+ | \`npm run lint\` | Lint with purus-lint |
102
+ `;
103
+ fs.writeFileSync(path.join(projectDir, "README.md"), readme);
104
+
105
+ // .gitignore
106
+ const gitignore = `dist/
107
+ node_modules/
108
+ `;
109
+ fs.writeFileSync(path.join(projectDir, ".gitignore"), gitignore);
110
+
111
+ console.log(" config.purus");
112
+ console.log(" .prettierrc");
113
+ console.log(" .gitignore");
114
+ console.log(" README.md");
115
+ console.log(" src/main.purus");
116
+
117
+ // npm init
118
+ console.log("");
119
+ if (yesFlag) {
120
+ console.log("Running npm init -y...");
121
+ spawnSync("npm", ["init", "-y"], {
122
+ cwd: projectDir,
123
+ stdio: "inherit",
124
+ shell: true,
125
+ });
126
+ } else {
127
+ console.log("Running npm init...");
128
+ spawnSync("npm", ["init"], {
129
+ cwd: projectDir,
130
+ stdio: "inherit",
131
+ shell: true,
132
+ });
133
+ }
134
+
135
+ // Add scripts to package.json
136
+ const pkgPath = path.join(projectDir, "package.json");
137
+ if (fs.existsSync(pkgPath)) {
138
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
139
+ pkg.scripts = {
140
+ ...(pkg.scripts || {}),
141
+ purus: "purus",
142
+ build: "purus build",
143
+ compile: "purus compile",
144
+ exec: "purus run",
145
+ format: "prettier --write ./src",
146
+ lint: "purus-lint",
147
+ };
148
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
149
+ console.log("\nAdded scripts to package.json");
150
+ }
151
+
152
+ // Ask about dependencies
153
+ let installDeps;
154
+ if (yesFlag) {
155
+ installDeps = true;
156
+ } else {
157
+ const answer = await question(rl, "\nInstall dependencies? (y/N) ");
158
+ installDeps =
159
+ answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
160
+ }
161
+
162
+ if (installDeps) {
163
+ const devDeps = [
164
+ "@puruslang/linter",
165
+ "@puruslang/prettier-plugin-purus",
166
+ "prettier",
167
+ "purus",
168
+ ];
169
+ console.log("\nInstalling devDependencies...");
170
+ for (const dep of devDeps) {
171
+ console.log(` ${dep}`);
172
+ }
173
+ console.log("");
174
+ spawnSync("npm", ["install", "--save-dev", ...devDeps], {
175
+ cwd: projectDir,
176
+ stdio: "inherit",
177
+ shell: true,
178
+ });
179
+ }
180
+
181
+ console.log("\nDone! To get started:");
182
+ console.log(` cd ${projectName}`);
183
+ if (!installDeps) {
184
+ console.log(" npm install");
185
+ }
186
+ console.log(" purus build");
187
+ } finally {
188
+ rl.close();
189
+ }
190
+ }
191
+
192
+ run().catch((err) => {
193
+ console.error(err.message);
194
+ process.exit(1);
195
+ });
@@ -616,7 +616,7 @@ function $64$username$47$core$46$MatchBody$BlockBody(param0) {
616
616
  $64$username$47$core$46$MatchBody$BlockBody.prototype.$tag = 1;
617
617
  $64$username$47$core$46$MatchBody$BlockBody.prototype.$name = "BlockBody";
618
618
  const _M0FP095_40moonbitlang_2fcore_2fbuiltin_2eStringBuilder_24as_24_40moonbitlang_2fcore_2fbuiltin_2eLogger = { method_0: _M0IP311moonbitlang4core7builtin13StringBuilderP311moonbitlang4core7builtin6Logger13write__string, method_1: _M0IP016_24default__implP311moonbitlang4core7builtin6Logger16write__substringGRP311moonbitlang4core7builtin13StringBuilderE, method_2: _M0IP311moonbitlang4core7builtin13StringBuilderP311moonbitlang4core7builtin6Logger11write__view, method_3: _M0IP311moonbitlang4core7builtin13StringBuilderP311moonbitlang4core7builtin6Logger11write__char };
619
- const _M0FP48username4core3cmd4main7version = "0.1.0";
619
+ const _M0FP48username4core3cmd4main7version = "0.2.0";
620
620
  const _M0FP311moonbitlang4core7builtin33brute__force__find_2econstr_2f209 = 0;
621
621
  const _M0FP311moonbitlang4core7builtin43boyer__moore__horspool__find_2econstr_2f195 = 0;
622
622
  function _M0FP311moonbitlang4core5abort5abortGRP311moonbitlang4core7builtin9ArrayViewGsEE(msg) {
@@ -7867,11 +7867,11 @@ function _M0FP48username4core3cmd4main8cmd__new(name) {
7867
7867
  _M0FP311moonbitlang4core7builtin7printlnGsE(`Error: cannot create src directory: ${msg}`);
7868
7868
  return undefined;
7869
7869
  }
7870
- const purus_json = `{\n \"name\": \"${name}\",\n \"version\": \"0.1.0\",\n \"main\": \"src/main.purus\"\n}\n`;
7870
+ const main_purus = "-- main.purus\n\nconst message be ///Hello, World///\nconsole.log[message]\n";
7871
7871
  let _try_err$3;
7872
7872
  _L$3: {
7873
7873
  _L$4: {
7874
- const _bind = _M0FP311moonbitlang1x2fs31write__string__to__file_2einner(`${name}/purus.json`, purus_json, "utf8");
7874
+ const _bind = _M0FP311moonbitlang1x2fs31write__string__to__file_2einner(`${name}/src/main.purus`, main_purus, "utf8");
7875
7875
  if (_bind.$tag === 1) {
7876
7876
  const _ok = _bind;
7877
7877
  _ok._0;
@@ -7892,11 +7892,11 @@ function _M0FP48username4core3cmd4main8cmd__new(name) {
7892
7892
  _M0FP311moonbitlang4core7builtin7printlnGsE(`Error: ${msg}`);
7893
7893
  return undefined;
7894
7894
  }
7895
- const main_purus = "-- main.purus\n\nconst message be ///Hello, World///\nconsole.log[message]\n";
7895
+ const gitignore = "*.js\nnode_modules/\n";
7896
7896
  let _try_err$4;
7897
7897
  _L$4: {
7898
7898
  _L$5: {
7899
- const _bind = _M0FP311moonbitlang1x2fs31write__string__to__file_2einner(`${name}/src/main.purus`, main_purus, "utf8");
7899
+ const _bind = _M0FP311moonbitlang1x2fs31write__string__to__file_2einner(`${name}/.gitignore`, gitignore, "utf8");
7900
7900
  if (_bind.$tag === 1) {
7901
7901
  const _ok = _bind;
7902
7902
  _ok._0;
@@ -7917,41 +7917,11 @@ function _M0FP48username4core3cmd4main8cmd__new(name) {
7917
7917
  _M0FP311moonbitlang4core7builtin7printlnGsE(`Error: ${msg}`);
7918
7918
  return undefined;
7919
7919
  }
7920
- const gitignore = "*.js\nnode_modules/\n";
7921
- let _try_err$5;
7922
- _L$5: {
7923
- _L$6: {
7924
- const _bind = _M0FP311moonbitlang1x2fs31write__string__to__file_2einner(`${name}/.gitignore`, gitignore, "utf8");
7925
- if (_bind.$tag === 1) {
7926
- const _ok = _bind;
7927
- _ok._0;
7928
- } else {
7929
- const _err = _bind;
7930
- _try_err$5 = _err._0;
7931
- break _L$6;
7932
- }
7933
- break _L$5;
7934
- }
7935
- let msg;
7936
- _L$7: {
7937
- const _IOError = _try_err$5;
7938
- const _msg = _IOError._0;
7939
- msg = _msg;
7940
- break _L$7;
7941
- }
7942
- _M0FP311moonbitlang4core7builtin7printlnGsE(`Error: ${msg}`);
7943
- return undefined;
7944
- }
7945
7920
  _M0FP311moonbitlang4core7builtin7printlnGsE(`Created project '${name}'`);
7946
- _M0FP311moonbitlang4core7builtin7printlnGsE(` ${name}/purus.json`);
7947
7921
  _M0FP311moonbitlang4core7builtin7printlnGsE(` ${name}/src/main.purus`);
7948
7922
  _M0FP311moonbitlang4core7builtin7printlnGsE(` ${name}/.gitignore`);
7949
7923
  }
7950
7924
  function _M0FP48username4core3cmd4main9cmd__init() {
7951
- if (_M0FP311moonbitlang1x2fs12path__exists("purus.json")) {
7952
- _M0FP311moonbitlang4core7builtin7printlnGsE("Error: purus.json already exists in current directory");
7953
- return undefined;
7954
- }
7955
7925
  if (!_M0FP311moonbitlang1x2fs12path__exists("src")) {
7956
7926
  let _try_err;
7957
7927
  _L: {
@@ -7978,53 +7948,28 @@ function _M0FP48username4core3cmd4main9cmd__init() {
7978
7948
  return undefined;
7979
7949
  }
7980
7950
  }
7981
- const purus_json = "{\n \"name\": \"my-project\",\n \"version\": \"0.1.0\",\n \"main\": \"src/main.purus\"\n}\n";
7982
- let _try_err;
7983
- _L: {
7984
- _L$2: {
7985
- const _bind = _M0FP311moonbitlang1x2fs31write__string__to__file_2einner("purus.json", purus_json, "utf8");
7986
- if (_bind.$tag === 1) {
7987
- const _ok = _bind;
7988
- _ok._0;
7989
- } else {
7990
- const _err = _bind;
7991
- _try_err = _err._0;
7992
- break _L$2;
7993
- }
7994
- break _L;
7995
- }
7996
- let msg;
7997
- _L$3: {
7998
- const _IOError = _try_err;
7999
- const _msg = _IOError._0;
8000
- msg = _msg;
8001
- break _L$3;
8002
- }
8003
- _M0FP311moonbitlang4core7builtin7printlnGsE(`Error: ${msg}`);
8004
- return undefined;
8005
- }
8006
7951
  if (!_M0FP311moonbitlang1x2fs12path__exists("src/main.purus")) {
8007
7952
  const main_purus = "-- main.purus\n\nconst message be ///Hello, World///\nconsole.log[message]\n";
8008
- let _try_err$2;
8009
- _L$2: {
8010
- _L$3: {
7953
+ let _try_err;
7954
+ _L: {
7955
+ _L$2: {
8011
7956
  const _bind = _M0FP311moonbitlang1x2fs31write__string__to__file_2einner("src/main.purus", main_purus, "utf8");
8012
7957
  if (_bind.$tag === 1) {
8013
7958
  const _ok = _bind;
8014
7959
  _ok._0;
8015
7960
  } else {
8016
7961
  const _err = _bind;
8017
- _try_err$2 = _err._0;
8018
- break _L$3;
7962
+ _try_err = _err._0;
7963
+ break _L$2;
8019
7964
  }
8020
- break _L$2;
7965
+ break _L;
8021
7966
  }
8022
7967
  let msg;
8023
- _L$4: {
8024
- const _IOError = _try_err$2;
7968
+ _L$3: {
7969
+ const _IOError = _try_err;
8025
7970
  const _msg = _IOError._0;
8026
7971
  msg = _msg;
8027
- break _L$4;
7972
+ break _L$3;
8028
7973
  }
8029
7974
  _M0FP311moonbitlang4core7builtin7printlnGsE(`Error: ${msg}`);
8030
7975
  return undefined;
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const { execFileSync } = require("child_process");
6
+ const { loadConfig } = require("./config.js");
7
+ const { compile } = require("./purus-core.js");
8
+
9
+ const args = process.argv.slice(3);
10
+
11
+ let file = null;
12
+ let directory = null;
13
+ let noHeader = false;
14
+
15
+ for (let i = 0; i < args.length; i++) {
16
+ if (args[i] === "--no-header") {
17
+ noHeader = true;
18
+ } else if (args[i] === "--directory" || args[i] === "-d") {
19
+ directory = args[++i];
20
+ } else if (!args[i].startsWith("-")) {
21
+ file = args[i];
22
+ }
23
+ }
24
+
25
+ if (file) {
26
+ // Single file - compile and run
27
+ const source = fs.readFileSync(file, "utf8");
28
+ const js = compile(source, { header: false });
29
+ const m = new (require("module"))();
30
+ m._compile(js, file);
31
+ } else {
32
+ let entryDir;
33
+ let useHeader;
34
+
35
+ if (directory) {
36
+ entryDir = path.resolve(directory);
37
+ useHeader = false;
38
+ } else {
39
+ const result = loadConfig();
40
+ if (!result) {
41
+ console.log("Error: no input file specified and no config.purus found");
42
+ console.log("");
43
+ console.log("Usage:");
44
+ console.log(" purus run <file> Run a single file");
45
+ console.log(
46
+ " purus run --directory <dir> Run all files in directory"
47
+ );
48
+ console.log(" purus run Run using config.purus");
49
+ process.exit(1);
50
+ }
51
+
52
+ const { config, configDir } = result;
53
+ entryDir = path.resolve(configDir, config.entry || "src");
54
+ useHeader = false;
55
+ }
56
+
57
+ if (!fs.existsSync(entryDir)) {
58
+ console.log(`Error: entry directory '${entryDir}' not found`);
59
+ process.exit(1);
60
+ }
61
+
62
+ const stat = fs.statSync(entryDir);
63
+ let files;
64
+
65
+ if (stat.isFile()) {
66
+ files = [entryDir];
67
+ } else {
68
+ files = findPurusFiles(entryDir);
69
+ }
70
+
71
+ if (files.length === 0) {
72
+ console.log(`No .purus files found in ${entryDir}`);
73
+ process.exit(0);
74
+ }
75
+
76
+ for (const f of files) {
77
+ const source = fs.readFileSync(f, "utf8");
78
+ const js = compile(source, { header: false });
79
+
80
+ const tmpFile = path.join(
81
+ require("os").tmpdir(),
82
+ `purus_run_${Date.now()}_${Math.random().toString(36).slice(2)}.js`
83
+ );
84
+ try {
85
+ fs.writeFileSync(tmpFile, js, "utf8");
86
+ execFileSync(process.execPath, [tmpFile], {
87
+ stdio: "inherit",
88
+ cwd: path.dirname(f),
89
+ });
90
+ } finally {
91
+ try {
92
+ fs.unlinkSync(tmpFile);
93
+ } catch {
94
+ // ignore cleanup errors
95
+ }
96
+ }
97
+ }
98
+ }
99
+
100
+ function findPurusFiles(dir) {
101
+ const results = [];
102
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
103
+ const fullPath = path.join(dir, entry.name);
104
+ if (entry.isDirectory()) {
105
+ results.push(...findPurusFiles(fullPath));
106
+ } else if (/\.(c|m)?purus$/.test(entry.name)) {
107
+ results.push(fullPath);
108
+ }
109
+ }
110
+ return results;
111
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "purus",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "A language that compiles to JavaScript — no Shift key required",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",