purus 0.2.1 → 0.4.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/bin/purus.js CHANGED
@@ -8,18 +8,19 @@ function printHelp() {
8
8
  console.log(`purus v${VERSION} - A language that compiles to JavaScript`);
9
9
  console.log("");
10
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");
11
+ console.log(" purus build [file|dir] Compile to JavaScript");
12
+ console.log(" purus build --entry <file|dir> Specify entry file or directory");
13
13
  console.log(" purus build --output <dir> Specify output directory");
14
14
  console.log(" purus build Compile using config.purus");
15
15
  console.log(" .purus -> .js");
16
16
  console.log(" .cpurus -> .cjs (CommonJS)");
17
17
  console.log(" .mpurus -> .mjs (ES Module)");
18
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");
19
+ console.log(" purus run [file|dir] Run without generating files");
20
+ console.log(" purus run --entry <file|dir> Run entry file or directory");
21
21
  console.log(" purus run Run using config.purus");
22
- console.log(" purus check <file> Syntax check only");
22
+ console.log(" purus check [file|dir] Syntax check only");
23
+ console.log(" purus check --entry <file|dir> Check entry file or directory");
23
24
  console.log(" purus new [name] [-y] Create a new project");
24
25
  console.log(" purus init Initialize project in current directory");
25
26
  console.log(" purus version Show version");
@@ -40,6 +41,14 @@ switch (cmd) {
40
41
  case "run":
41
42
  require("../lib/run-wrapper.js");
42
43
  break;
44
+ case "check":
45
+ require("../lib/check-wrapper.js");
46
+ break;
47
+ case "version":
48
+ case "--version":
49
+ case "-v":
50
+ console.log(`purus v${VERSION}`);
51
+ break;
43
52
  case "help":
44
53
  case "--help":
45
54
  case "-h":
@@ -7,8 +7,7 @@ const { compile } = require("./purus-core.js");
7
7
 
8
8
  const args = process.argv.slice(3);
9
9
 
10
- let file = null;
11
- let directory = null;
10
+ let entry = null;
12
11
  let output = null;
13
12
  let noHeader = false;
14
13
  let toStdout = false;
@@ -18,25 +17,44 @@ for (let i = 0; i < args.length; i++) {
18
17
  noHeader = true;
19
18
  } else if (args[i] === "--stdout") {
20
19
  toStdout = true;
21
- } else if (args[i] === "--directory" || args[i] === "-d") {
22
- directory = args[++i];
20
+ } else if (args[i] === "--entry" || args[i] === "-e") {
21
+ entry = args[++i];
23
22
  } else if (args[i] === "--output" || args[i] === "-o") {
24
23
  output = args[++i];
25
24
  } else if (!args[i].startsWith("-")) {
26
- file = args[i];
25
+ entry = args[i];
27
26
  }
28
27
  }
29
28
 
30
- if (file) {
31
- // Single file - delegate to MoonBit compiler
32
- require("./purus-compiler.js");
29
+ if (entry && fs.existsSync(entry) && fs.statSync(entry).isFile() && /\.(c|m)?purus$/.test(entry)) {
30
+ // Single file - handle directly via compile API
31
+ const source = fs.readFileSync(entry, "utf8");
32
+ const useHeader = !noHeader;
33
+ const js = compile(source, { header: useHeader });
34
+
35
+ if (toStdout) {
36
+ process.stdout.write(js);
37
+ } else {
38
+ let ext = ".js";
39
+ if (entry.endsWith(".cpurus")) ext = ".cjs";
40
+ else if (entry.endsWith(".mpurus")) ext = ".mjs";
41
+ const base = entry.replace(/\.(c|m)?purus$/, "");
42
+ const outputFile = output
43
+ ? path.join(path.resolve(output), path.basename(base) + ext)
44
+ : base + ext;
45
+ if (output) {
46
+ fs.mkdirSync(path.resolve(output), { recursive: true });
47
+ }
48
+ fs.writeFileSync(outputFile, js);
49
+ console.log(`Compiled ${entry} -> ${outputFile}`);
50
+ }
33
51
  } else {
34
52
  let entryDir;
35
53
  let outputDir;
36
54
  let useHeader;
37
55
 
38
- if (directory) {
39
- entryDir = path.resolve(directory);
56
+ if (entry) {
57
+ entryDir = path.resolve(entry);
40
58
  outputDir = output ? path.resolve(output) : path.resolve("dist");
41
59
  useHeader = !noHeader;
42
60
 
@@ -56,10 +74,8 @@ if (file) {
56
74
  console.log("Error: no input file specified and no config.purus found");
57
75
  console.log("");
58
76
  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
- );
77
+ console.log(" purus build <file|dir> Compile a file or directory");
78
+ console.log(" purus build --entry <file|dir> Specify entry");
63
79
  console.log(
64
80
  " purus build Compile using config.purus"
65
81
  );
@@ -0,0 +1,97 @@
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 entry = null;
11
+
12
+ for (let i = 0; i < args.length; i++) {
13
+ if (args[i] === "--entry" || args[i] === "-e") {
14
+ entry = args[++i];
15
+ } else if (!args[i].startsWith("-")) {
16
+ entry = args[i];
17
+ }
18
+ }
19
+
20
+ if (entry && fs.existsSync(entry) && fs.statSync(entry).isFile()) {
21
+ checkFile(entry);
22
+ } else {
23
+ let entryDir;
24
+
25
+ if (entry) {
26
+ entryDir = path.resolve(entry);
27
+ } else {
28
+ const result = loadConfig();
29
+ if (!result) {
30
+ console.log("Error: no input file specified and no config.purus found");
31
+ console.log("");
32
+ console.log("Usage:");
33
+ console.log(" purus check <file|dir> Check a file or directory");
34
+ console.log(" purus check --entry <file|dir> Specify entry");
35
+ console.log(" purus check Check using config.purus");
36
+ process.exit(1);
37
+ }
38
+
39
+ const { config, configDir } = result;
40
+ entryDir = path.resolve(configDir, config.entry || "src");
41
+ }
42
+
43
+ if (!fs.existsSync(entryDir)) {
44
+ console.log(`Error: entry '${entryDir}' not found`);
45
+ process.exit(1);
46
+ }
47
+
48
+ const stat = fs.statSync(entryDir);
49
+ let files;
50
+
51
+ if (stat.isFile()) {
52
+ files = [entryDir];
53
+ } else {
54
+ files = findPurusFiles(entryDir);
55
+ }
56
+
57
+ if (files.length === 0) {
58
+ console.log(`No .purus files found in ${entryDir}`);
59
+ process.exit(0);
60
+ }
61
+
62
+ let errors = 0;
63
+ for (const f of files) {
64
+ if (!checkFile(f)) errors++;
65
+ }
66
+
67
+ if (errors > 0) {
68
+ console.log(`\n${errors} file${errors === 1 ? "" : "s"} with errors.`);
69
+ process.exit(1);
70
+ } else {
71
+ console.log(`${files.length} file${files.length === 1 ? "" : "s"} checked. No errors.`);
72
+ }
73
+ }
74
+
75
+ function checkFile(file) {
76
+ try {
77
+ const source = fs.readFileSync(file, "utf8");
78
+ compile(source, { header: false });
79
+ return true;
80
+ } catch (err) {
81
+ console.log(`${file}: ${err.message}`);
82
+ return false;
83
+ }
84
+ }
85
+
86
+ function findPurusFiles(dir) {
87
+ const results = [];
88
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
89
+ const fullPath = path.join(dir, entry.name);
90
+ if (entry.isDirectory()) {
91
+ results.push(...findPurusFiles(fullPath));
92
+ } else if (/\.(c|m)?purus$/.test(entry.name) && entry.name !== "config.purus") {
93
+ results.push(fullPath);
94
+ }
95
+ }
96
+ return results;
97
+ }
package/lib/create.js CHANGED
@@ -46,15 +46,18 @@ async function run() {
46
46
 
47
47
  // config.purus
48
48
  const configPurus = `-- Purus Configuration
49
-
50
49
  const entry be ///src///
51
50
  const output be ///dist///
52
51
  const header be true
53
52
 
54
53
  -- Linter settings
55
54
  const lint.no-var be ///warn///
55
+ const lint.no-nil be ///warn///
56
56
  const lint.indent-size be 2
57
57
  const lint.max-line-length be ///off///
58
+ const lint.no-trailing-whitespace be ///warn///
59
+ const lint.no-unused-import be ///warn///
60
+ const lint.consistent-naming be ///warn///
58
61
  `;
59
62
  fs.writeFileSync(path.join(projectDir, "config.purus"), configPurus);
60
63
 
@@ -154,9 +157,9 @@ node_modules/
154
157
  if (yesFlag) {
155
158
  installDeps = true;
156
159
  } else {
157
- const answer = await question(rl, "\nInstall dependencies? (y/N) ");
160
+ const answer = await question(rl, "\nInstall dependencies? (Y/n) ");
158
161
  installDeps =
159
- answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
162
+ answer === "" || answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
160
163
  }
161
164
 
162
165
  if (installDeps) {