eolang 0.35.1 → 0.35.2

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/Formula/eolang.rb CHANGED
@@ -7,9 +7,9 @@ require "language/node"
7
7
  class Eolang < Formula
8
8
  desc "Command-line Tool-Kit"
9
9
  homepage "https://github.com/objectionary/eoc"
10
- url "https://github.com/objectionary/eoc/archive/refs/tags/0.34.1.tar.gz"
11
- version "0.34.1"
12
- sha256 "ecf7f19115086fadbe1785b789378928d81dc8f0e3aa154b268f3a747c80fd01"
10
+ url "https://github.com/objectionary/eoc/archive/refs/tags/0.35.1.tar.gz"
11
+ version "0.35.1"
12
+ sha256 "694218ea2ab13179be731ab7d671ba5f7ebe9a8aa9fc6b5d695d699180879466"
13
13
  license "MIT"
14
14
 
15
15
  depends_on "node"
@@ -0,0 +1,25 @@
1
+ #
2
+ # SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com
3
+ # SPDX-License-Identifier: MIT
4
+ #
5
+
6
+ require "language/node"
7
+ class EolangAT0351 < Formula
8
+ desc "Command-line Tool-Kit"
9
+ homepage "https://github.com/objectionary/eoc"
10
+ url "https://github.com/objectionary/eoc/archive/refs/tags/0.34.1.tar.gz"
11
+ version "0.34.1"
12
+ sha256 "ecf7f19115086fadbe1785b789378928d81dc8f0e3aa154b268f3a747c80fd01"
13
+ license "MIT"
14
+
15
+ depends_on "node"
16
+
17
+ def install
18
+ system "npm", "install", *std_npm_args
19
+ bin.install_symlink Dir["#{libexec}/bin/*"]
20
+ end
21
+
22
+ test do
23
+ system "#{bin}/eoc", "--version"
24
+ end
25
+ end
package/README.md CHANGED
@@ -20,14 +20,14 @@ First, you install [npm][npm-install] and [Java SE][java-se].
20
20
  Then, you install [eolang][npm] package, using [npm][npm-install]:
21
21
 
22
22
  ```bash
23
- npm install -g eolang@0.35.0
23
+ npm install -g eolang@0.35.1
24
24
  ```
25
25
 
26
26
  You can also use [Homebrew] (on macOS):
27
27
 
28
28
  ```bash
29
29
  brew tap objectionary/eoc https://github.com/objectionary/eoc
30
- brew install objectionary/eoc/eolang@0.35.0
30
+ brew install objectionary/eoc/eolang@0.35.1
31
31
  ```
32
32
 
33
33
  Or install it via [Nix flakes](https://nixos.wiki/wiki/Flakes):
@@ -115,41 +115,29 @@ That's it.
115
115
  You can also do many other things with `eoc` commands
116
116
  (the flow is explained in [this blog post][blog]):
117
117
 
118
- * `register` finds necessary `.eo` files and registers them in a JSON catalog
119
- * `assemble` parses `.eo` files into `.xmir`, optimizes them,
120
- and pulls foreign EO objects
121
- * `transpile` converts `.xmir` files to the target programming
122
- language (Java by default)
123
- * `compile` converts target language sources (e.g., `.java`)
124
- to binaries (e.g., `.class`)
125
- * `link` puts all binaries together into a single executable binary
126
- * `dataize` dataizes a single object from the executable binary
127
- * `test` dataizes all visible unit tests
128
- * `lint` finds style-related errors in EO and XMIR files
129
- * `jeo:disassemble` converts Java `.class` files to `.xmir`
130
- (via [jeo](https://github.com/objectionary/jeo-maven-plugin))
131
- * `jeo:assemble` converts `.xmir` files to Java `.class` files
132
- (via [jeo](https://github.com/objectionary/jeo-maven-plugin))
133
-
134
- There are also commands that help manipulate with XMIR and EO sources
135
- (the list is not completed, while some of them are not implemented as of yet):
136
-
137
- * `audit` inspects all required packages and reports their status
138
- * `foreign` inspects all objects found in the program after the `assemble` step
139
- * `print` generates `.eo` files from `.xmir` files
140
- * `generate_comments` generates `.json` files with LLM-generated
141
- documentation for `.eo` structures
142
- * `docs` generates HTML documentation from `.xmir` files
143
- * `latex` generates `.tex` files from `.eo` sources
144
- * `fmt` formats `.eo` files in the source directory
145
- * `normalize` normalizes `.eo` files via phi-calculus rewriting using
146
- [phino](https://github.com/objectionary/phino) (must be installed separately);
147
- original files are saved to `.eoc/before-normalize/` for debugging
148
- * ~~`translate` converts Java/C++/Python/etc. program to EO program~~
149
- * ~~`demu` removes `cage` and `memory` objects~~
150
- * ~~`dejump` removes `goto` objects~~
151
- * ~~`infer` suggests object names where it's possible to infer them~~
152
- * ~~`flatten` moves inner objects to upper level~~
118
+ <!-- BEGIN COMMANDS SECTION -->
119
+ * `audit` Inspect all packages and report their status
120
+ * `foreign` Inspect and print the list of foreign objects
121
+ * `clean` Delete all temporary files
122
+ * `register` Register all visible EO source files
123
+ * `parse` Parse EO files into XMIR
124
+ * `assemble` Parse EO files into XMIR and join them with required dependencies
125
+ * `print` Generate EO files from XMIR files
126
+ * `lint` Lint XMIR files and fail if any issues inside
127
+ * `resolve` Resolve all the dependencies required for compilation
128
+ * `transpile` Convert EO files into target language
129
+ * `compile` Compile target language sources into binaries
130
+ * `link` Link together all binaries into a single executable binary
131
+ * `dataize` Run the single executable binary and dataize an object
132
+ * `test` Run all visible unit tests
133
+ * `docs` Generate documentation from XMIR files
134
+ * `generate_comments` Generate documentation with LLM
135
+ * `jeo:disassemble` Disassemble .class files to .xmir files
136
+ * `jeo:assemble` Assemble .xmir files to .class files
137
+ * `latex` Generate LaTeX files from EO sources
138
+ * `normalize` Normalize EO files using phi-calculus normalization via phino
139
+ * `fmt` Format EO files in the source directory
140
+ <!-- END COMMANDS SECTION -->
153
141
 
154
142
  This command line toolkit simply integrates other tools available in
155
143
  the [@objectionary](https://github.com/objectionary) GitHub organization.
package/eo-version.txt CHANGED
@@ -1 +1 @@
1
- 0.61.0
1
+ 0.61.1
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com
2
2
  # SPDX-License-Identifier: MIT
3
3
 
4
- distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.14/apache-maven-3.9.14-bin.zip
4
+ distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip
@@ -13,7 +13,7 @@
13
13
  <plugins>
14
14
  <plugin>
15
15
  <artifactId>maven-enforcer-plugin</artifactId>
16
- <version>3.6.2</version>
16
+ <version>3.6.3</version>
17
17
  <executions>
18
18
  <execution>
19
19
  <goals>
@@ -77,7 +77,7 @@
77
77
  </plugin>
78
78
  <plugin>
79
79
  <artifactId>maven-surefire-plugin</artifactId>
80
- <version>3.5.5</version>
80
+ <version>3.5.6</version>
81
81
  <configuration>
82
82
  <skipTests>true</skipTests>
83
83
  </configuration>
@@ -120,7 +120,7 @@
120
120
  </plugin>
121
121
  <plugin>
122
122
  <artifactId>maven-surefire-plugin</artifactId>
123
- <version>3.5.5</version>
123
+ <version>3.5.6</version>
124
124
  <configuration>
125
125
  <skipTests>false</skipTests>
126
126
  <failIfNoTests>true</failIfNoTests>
@@ -158,7 +158,7 @@
158
158
  <dependency>
159
159
  <groupId>org.junit.jupiter</groupId>
160
160
  <artifactId>junit-jupiter-api</artifactId>
161
- <version>6.0.3</version>
161
+ <version>6.1.0</version>
162
162
  <scope>test</scope>
163
163
  <exclusions>
164
164
  <exclusion>
@@ -182,7 +182,7 @@
182
182
  <dependency>
183
183
  <groupId>org.junit.jupiter</groupId>
184
184
  <artifactId>junit-jupiter-engine</artifactId>
185
- <version>6.0.3</version>
185
+ <version>6.1.0</version>
186
186
  <scope>test</scope>
187
187
  <exclusions>
188
188
  <exclusion>
@@ -206,7 +206,7 @@
206
206
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
207
207
  <heap-size>undefined</heap-size>
208
208
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
209
- <junit.version>6.0.3</junit.version>
210
- <jeo.version>0.15.0</jeo.version>
209
+ <junit.version>6.1.0</junit.version>
210
+ <jeo.version>0.15.2</jeo.version>
211
211
  </properties>
212
212
  </project>
package/mvnw/pom.xml CHANGED
@@ -10,13 +10,13 @@
10
10
  <version>0.0.0</version>
11
11
  <packaging>jar</packaging>
12
12
  <properties>
13
- <jeo.version>0.15.0</jeo.version>
13
+ <jeo.version>0.15.2</jeo.version>
14
14
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15
15
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
16
16
  <eo.version>undefined</eo.version>
17
17
  <heap-size>undefined</heap-size>
18
18
  <stack-size>undefined</stack-size>
19
- <junit.version>6.0.3</junit.version>
19
+ <junit.version>6.1.0</junit.version>
20
20
  </properties>
21
21
  <dependencies>
22
22
  <dependency>
@@ -34,7 +34,7 @@
34
34
  <plugins>
35
35
  <plugin>
36
36
  <artifactId>maven-enforcer-plugin</artifactId>
37
- <version>3.6.2</version>
37
+ <version>3.6.3</version>
38
38
  <executions>
39
39
  <execution>
40
40
  <goals>
@@ -98,7 +98,7 @@
98
98
  </plugin>
99
99
  <plugin>
100
100
  <artifactId>maven-surefire-plugin</artifactId>
101
- <version>3.5.5</version>
101
+ <version>3.5.6</version>
102
102
  <configuration>
103
103
  <skipTests>true</skipTests>
104
104
  </configuration>
@@ -160,7 +160,7 @@
160
160
  </plugin>
161
161
  <plugin>
162
162
  <artifactId>maven-surefire-plugin</artifactId>
163
- <version>3.5.5</version>
163
+ <version>3.5.6</version>
164
164
  <configuration>
165
165
  <skipTests>false</skipTests>
166
166
  <failIfNoTests>true</failIfNoTests>
package/package.json CHANGED
@@ -4,8 +4,8 @@
4
4
  "eoc": "./src/eoc.js"
5
5
  },
6
6
  "dependencies": {
7
- "@langchain/core": "^0.3.55",
8
- "@langchain/openai": "^0.6.0",
7
+ "@langchain/core": "^1.0.0",
8
+ "@langchain/openai": "^1.0.0",
9
9
  "colors": "^1.4.0",
10
10
  "commander": "^12.1.0",
11
11
  "eo2js": "^0.0.8",
@@ -27,9 +27,8 @@
27
27
  "grunt-eslint": "^26.0.0",
28
28
  "grunt-mocha-test": "^0.13.3",
29
29
  "istanbul": "^0.4.5",
30
- "mocha": "^11.7.5",
31
- "nyc": "^18.0.0",
32
- "patch-package": "^8.0.0"
30
+ "mocha": "^11.7.6",
31
+ "nyc": "^18.0.0"
33
32
  },
34
33
  "engines": {
35
34
  "node": ">6.0",
@@ -71,8 +70,7 @@
71
70
  "repository": "objectionary/eoc",
72
71
  "scripts": {
73
72
  "coverage": "nyc --reporter=lcov --reporter=text-summary mocha test/**/*.js --timeout 1200000",
74
- "postinstall": "node scripts/postinstall.js",
75
73
  "test": "mocha 'test/**/*.js' --timeout 1200000"
76
74
  },
77
- "version": "0.35.1"
75
+ "version": "0.35.2"
78
76
  }
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+
7
+ const assert = require('assert');
8
+ const { commandsDescription } = require("../src/eoc");
9
+
10
+ function escapeRegex(str) {
11
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12
+ }
13
+
14
+ function updateSection(sectionName, newContent, readMeContent) {
15
+ const start = `<!-- BEGIN ${sectionName.toUpperCase()} SECTION -->`;
16
+ const end = `<!-- END ${sectionName.toUpperCase()} SECTION -->`;
17
+ const regex = new RegExp(
18
+ `(${escapeRegex(start)})([\\s\\S]*?)(${escapeRegex(end)})`,
19
+ "g"
20
+ );
21
+ return readMeContent.replace(regex, `$1\n${newContent}$3`);
22
+ }
23
+
24
+ function bulletListTemplate(rows) {
25
+ return `${rows.map(([cmd, desc]) => `* \`${cmd}\` ${desc}`).join("\n") }\n`;
26
+ }
27
+
28
+ function modifyReadme(commands,fs) {
29
+ assert.ok(commands.length > 0,'Commands should have rows')
30
+ const commandsMarkdown = bulletListTemplate(commands);
31
+ assert.ok(commandsMarkdown.length > 0,"commandsMarkdown result should have text")
32
+ let readMeContent = fs.readFileSync('README.md', "utf8");
33
+ assert.ok(readMeContent.length > 0,"readMeContent should have text")
34
+ readMeContent = updateSection('commands', commandsMarkdown, readMeContent);
35
+ assert.ok(readMeContent.length > 0,"readMeContent should sill have text after modification")
36
+ fs.writeFileSync('README.md',readMeContent);
37
+ }
38
+
39
+ function syncCommandsToReadme(fs)
40
+ {
41
+ modifyReadme(commandsDescription(),fs);
42
+ }
43
+
44
+ module.exports = {
45
+ bulletListTemplate, updateSection, modifyReadme, syncCommandsToReadme
46
+ };
47
+
48
+ if (require.main === module) {
49
+ syncCommandsToReadme(require("fs"));
50
+ };
@@ -7,15 +7,57 @@ const rel = require('relative');
7
7
  const path = require('path');
8
8
  const fs = require('fs');
9
9
 
10
+ /**
11
+ * Extract the first balanced JSON array from a string, ignoring any trailing
12
+ * bytes that may have been left over by a non-atomic writer (observed on
13
+ * Windows CI, see issue #782).
14
+ * @param {String} text - Raw file contents
15
+ * @return {String} Substring spanning the first complete `[...]` array
16
+ */
17
+ function firstJsonArray(text) {
18
+ const body = text.charCodeAt(0) === 0xFEFF ? text.slice(1) : text;
19
+ let depth = 0;
20
+ let start = -1;
21
+ let inString = false;
22
+ let escape = false;
23
+ for (let i = 0; i < body.length; i += 1) {
24
+ const ch = body[i];
25
+ if (inString) {
26
+ if (escape) {
27
+ escape = false;
28
+ } else if (ch === '\\') {
29
+ escape = true;
30
+ } else if (ch === '"') {
31
+ inString = false;
32
+ }
33
+ } else if (ch === '"') {
34
+ inString = true;
35
+ } else if (ch === '[') {
36
+ if (depth === 0) {
37
+ start = i;
38
+ }
39
+ depth += 1;
40
+ } else if (ch === ']') {
41
+ depth -= 1;
42
+ if (depth === 0 && start >= 0) {
43
+ return body.slice(start, i + 1);
44
+ }
45
+ }
46
+ }
47
+ throw new SyntaxError('No complete JSON array found in foreign catalog');
48
+ }
49
+
10
50
  /**
11
51
  * Inspects and prints the list of foreign objects.
12
52
  * @param {Hash} opts - All options
13
53
  */
14
54
  module.exports = function(opts) {
15
- const file = path.resolve(opts.target, 'eo-foreign.json'),
16
- all = JSON.parse(fs.readFileSync(file, 'utf8'));
55
+ const file = path.resolve(opts.target, 'eo-foreign.json');
56
+ const all = JSON.parse(firstJsonArray(fs.readFileSync(file, 'utf8')));
17
57
  console.info('There are %d objects in %s:', all.length, rel(file));
18
58
  all.forEach((obj) => {
19
59
  console.info(' %s', obj.id);
20
60
  });
21
61
  };
62
+
63
+ module.exports.firstJsonArray = firstJsonArray;
@@ -5,6 +5,7 @@
5
5
  const rel = require('relative');
6
6
  const {mvnw, flags} = require('../../mvnw');
7
7
  const {elapsed} = require('../../elapsed');
8
+ const {verifyJavac} = require('../../jdk');
8
9
  const path = require('path');
9
10
 
10
11
  /**
@@ -13,6 +14,7 @@ const path = require('path');
13
14
  * @return {Promise} of compile task
14
15
  */
15
16
  module.exports = function(opts) {
17
+ verifyJavac();
16
18
  const target = path.resolve(opts.target);
17
19
  return elapsed(async (tracked) => {
18
20
  const r = await mvnw(goals().concat(flags(opts)), opts.target, opts.batch);
@@ -6,6 +6,7 @@
6
6
  const rel = require('relative');
7
7
  const {mvnw, flags} = require('../../mvnw');
8
8
  const {elapsed} = require('../../elapsed');
9
+ const {verifyJavac} = require('../../jdk');
9
10
  const path = require('path');
10
11
 
11
12
  /**
@@ -14,6 +15,7 @@ const path = require('path');
14
15
  * @return {Promise} of link task
15
16
  */
16
17
  module.exports = function(opts) {
18
+ verifyJavac();
17
19
  const jar = path.resolve(opts.target, 'eoc.jar');
18
20
  return elapsed(async (tracked) => {
19
21
  const r = await mvnw(goals().concat(flags(opts)), opts.target, opts.batch);
@@ -5,6 +5,16 @@
5
5
 
6
6
  const {mvnw, flags} = require('../../mvnw');
7
7
  const {elapsed} = require('../../elapsed');
8
+ const {verifyJavac} = require('../../jdk');
9
+
10
+ /**
11
+ * Commands whose Maven goals require `javac` to be on the PATH.
12
+ * Anything that triggers the maven-compiler-plugin (or surefire test
13
+ * compilation) must be listed here so we can fail fast with a clear
14
+ * diagnostic instead of letting Maven die with `release version 11
15
+ * not supported`.
16
+ */
17
+ const JAVAC_COMMANDS = ['compile', 'link', 'test'];
8
18
 
9
19
  /**
10
20
  * Runs multiple Maven goals in a single Maven invocation.
@@ -14,6 +24,9 @@ const {elapsed} = require('../../elapsed');
14
24
  * @return {Promise} of pipeline task
15
25
  */
16
26
  module.exports = function(coms, commands, opts, maven = mvnw) {
27
+ if (commands.some((cmd) => JAVAC_COMMANDS.includes(cmd))) {
28
+ verifyJavac();
29
+ }
17
30
  return elapsed(async (tracked) => {
18
31
  const {goals, extras} = collect(coms, commands, opts);
19
32
  const result = await maven(goals.concat(flags(opts)).concat(extras), opts.target, opts.batch);
@@ -4,18 +4,28 @@
4
4
  */
5
5
 
6
6
  const {mvnw, flags} = require('../../mvnw');
7
+ const {verifyJavac} = require('../../jdk');
7
8
 
8
9
  /**
9
10
  * Command to run all available unit tests.
10
11
  * @param {Object} opts - All options
12
+ * @param {Function} maven - Maven runner, defaults to mvnw
11
13
  * @return {Promise} of compile task
12
14
  */
13
- module.exports = function(opts) {
14
- return mvnw(
15
- [
16
- 'surefire:test',
17
- `-Dstack-size=${opts.stack}`,
18
- `-Dheap-size=${opts.heap}`,
19
- ].concat(flags(opts))
20
- );
15
+ module.exports = function(opts, maven = mvnw) {
16
+ verifyJavac();
17
+ const args = [
18
+ 'surefire:test',
19
+ `-Dstack-size=${opts.stack}`,
20
+ `-Dheap-size=${opts.heap}`,
21
+ ];
22
+ if (opts.object) {
23
+ const parts = opts.object.split('.');
24
+ const method = parts.pop().replace(/-/g, '_');
25
+ const obj = parts.pop().replace(/-/g, '_');
26
+ const pkg = parts.map((p) => `EO${p.replace(/-/g, '_')}`).join('.');
27
+ const cls = `EO${obj}*Test`;
28
+ args.push(`-Dtest=${pkg ? `org.eolang.${pkg}.${cls}` : `org.eolang.${cls}`}#${method}`);
29
+ }
30
+ return maven(args.concat(flags(opts)));
21
31
  };
package/src/elapsed.js CHANGED
@@ -29,7 +29,7 @@ module.exports.elapsed = function elapsed(task) {
29
29
  } else if (duration < 60 * 1000) {
30
30
  extended = `${Math.ceil(duration / 1000)}s`;
31
31
  } else {
32
- extended = `${Math.ceil(duration / 3600000)}min`;
32
+ extended = `${Math.ceil(duration / (60 * 1000))}min`;
33
33
  }
34
34
  const msg = `${message} in ${extended}`;
35
35
  console.info(msg);
package/src/eoc.js CHANGED
@@ -234,6 +234,7 @@ program.command('compile')
234
234
  program.command('link')
235
235
  .description('Link together all binaries into a single executable binary')
236
236
  .action(async (str, opts) => {
237
+ pin(program.opts());
237
238
  clear(str);
238
239
  if (program.opts().alone === undefined) {
239
240
  await pipe()(coms(), ['register', 'assemble', 'lint', 'resolve', 'transpile', 'compile', 'link'], program.opts());
@@ -265,6 +266,7 @@ program.command('test')
265
266
  .description('Run all visible unit tests')
266
267
  .option('--stack <size>', 'Set stack size for the virtual machine', '64M')
267
268
  .option('--heap <size>', 'Set the heap size for the VM', '256M')
269
+ .option('--object <name>', 'Run a single test object by its full EO name, e.g. foo.app.works-fine')
268
270
  .action(async (str, opts) => {
269
271
  pin(program.opts());
270
272
  clear(str);
@@ -340,6 +342,7 @@ program.command('jeo:assemble')
340
342
  'classes'
341
343
  )
342
344
  .action((str, opts) => {
345
+ pin(program.opts());
343
346
  coms().jeo_assemble({...program.opts(), ...str});
344
347
  });
345
348
 
@@ -369,17 +372,24 @@ program.command('fmt')
369
372
  await pipe()(coms(), ['register', 'parse'], program.opts());
370
373
  await coms().print({
371
374
  printInput: '1-parse',
372
- printOutput: program.opts().sources,
375
+ printOutput: path.resolve(program.opts().sources),
373
376
  ...program.opts()
374
377
  });
375
378
  });
376
379
 
377
- try {
378
- program.parse(process.argv);
379
- } catch (e) {
380
- console.error(e.message);
381
- console.debug(e.stack);
382
- process.exit(1);
380
+ if (require.main === module) {
381
+ try {
382
+ program.parse(process.argv);
383
+ } catch (e) {
384
+ console.error(e.message);
385
+ console.debug(e.stack);
386
+ process.exit(1);
387
+ }
388
+ }
389
+
390
+ module.exports.commandsDescription = function commandsDescription() {
391
+ return program.commands
392
+ .map(c => [c.name(),c.description()]);
383
393
  }
384
394
 
385
395
  /**
package/src/jdk.js ADDED
@@ -0,0 +1,65 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ const {execSync} = require('child_process');
7
+
8
+ /**
9
+ * Default executor used when no override is supplied. Runs the command
10
+ * synchronously, captures its output, and returns it as a Buffer.
11
+ * Stderr is captured (javac prints its version to stderr) so we can
12
+ * surface it back if anything goes wrong.
13
+ *
14
+ * @param {String} cmd - The command to execute.
15
+ * @return {Buffer} The combined stdout/stderr output.
16
+ */
17
+ function defaultExec(cmd) {
18
+ return execSync(cmd, {stdio: ['ignore', 'pipe', 'pipe']});
19
+ }
20
+
21
+ /**
22
+ * Build the user-facing error message that we want to print when
23
+ * `javac` cannot be located or executed. The message lists the
24
+ * common ways to install a full JDK on each platform, since the
25
+ * most common cause of this error is that the user has installed
26
+ * a JRE (or none at all) instead of a JDK.
27
+ *
28
+ * @param {Error} cause - The underlying error from the exec attempt.
29
+ * @return {String} The user-facing diagnostic.
30
+ */
31
+ function missingJavacMessage(cause) {
32
+ const lines = [
33
+ '`javac` was not found on your PATH.',
34
+ 'EO needs a full JDK (not just a JRE) to compile Java sources.',
35
+ 'Please install OpenJDK 11 or newer and make sure `javac` is on your PATH.',
36
+ ' Debian/Ubuntu: sudo apt-get install openjdk-21-jdk',
37
+ ' macOS: brew install --cask temurin',
38
+ ' Windows: https://adoptium.net/'
39
+ ];
40
+ if (cause && cause.message) {
41
+ lines.push(`Underlying error: ${cause.message.toString().trim()}`);
42
+ }
43
+ return lines.join('\n');
44
+ }
45
+
46
+ /**
47
+ * Verify that `javac` is available on the current PATH. Throws an
48
+ * Error with a clear, actionable message when it is not, and is a
49
+ * no-op otherwise. The actual command runner is injectable so that
50
+ * tests can stub it out without spawning a real subprocess.
51
+ *
52
+ * @param {Function} [exec] - Optional command runner (mainly for tests).
53
+ * Should accept a single string command and
54
+ * either return the captured output or throw
55
+ * on non-zero exit.
56
+ * @return {void}
57
+ */
58
+ module.exports.verifyJavac = function(exec) {
59
+ const run = exec || defaultExec;
60
+ try {
61
+ run('javac -version');
62
+ } catch (cause) {
63
+ throw new Error(missingJavacMessage(cause), {cause});
64
+ }
65
+ };
package/src/mvnw.js CHANGED
@@ -42,7 +42,7 @@ module.exports.flags = function(opts) {
42
42
  console.debug('Sources in %s', rel(sources));
43
43
  const target = path.resolve(opts.target);
44
44
  console.debug('Target in %s', rel(target));
45
- if (opts.parser && !parserVersion.exists(opts.parser)) {
45
+ if (opts.parser && !opts.parser.endsWith('-SNAPSHOT') && !parserVersion.exists(opts.parser)) {
46
46
  console.error(colors.red(
47
47
  `Parser version ${opts.parser} is not available in Maven Central.\n` +
48
48
  `Please check available versions at: https://repo.maven.apache.org/maven2/org/eolang/eo-maven-plugin/\n` +
@@ -65,6 +65,8 @@ module.exports.flags = function(opts) {
65
65
  `-Deo.placedFormat=csv`,
66
66
  `-Deo.skipLinting=${opts.blind ? 'true' : 'false'}`,
67
67
  opts.trackTransformationSteps ? '-Deo.trackTransformationSteps' : '',
68
+ '-Dorg.slf4j.simpleLogger.showDateTime=true',
69
+ '-Dorg.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss',
68
70
  ].filter(flag => flag !== '');
69
71
  };
70
72
 
@@ -200,7 +202,7 @@ function print() {
200
202
  } else if (duration < 60 * 1000) {
201
203
  elapsed = `${Math.ceil(duration / 1000)}s`;
202
204
  } else {
203
- elapsed = `${Math.ceil(duration / 3600000)}min`;
205
+ elapsed = `${Math.ceil(duration / (60 * 1000))}min`;
204
206
  }
205
207
  process.stdout.write(
206
208
  colors.yellow(`[${phase}] ${elapsed}; ${count(target, 0)} files generated so far...`)
@@ -26,19 +26,27 @@ const request = require('sync-request'),
26
26
  }
27
27
  return version.value;
28
28
  },
29
+ /**
30
+ * Build the Maven Central URL of a parser version POM.
31
+ * @param {String} ver - Version to locate, for example '0.23.1'
32
+ * @return {String} Full URL of the eo-maven-plugin POM
33
+ */
34
+ url(ver) {
35
+ const repo = 'org/eolang/eo-maven-plugin',
36
+ artifactId = 'eo-maven-plugin';
37
+ return `https://repo.maven.apache.org/maven2/${repo}/${ver}/${artifactId}-${ver}.pom`;
38
+ },
29
39
  /**
30
40
  * Check if a specific parser version exists in Maven Central.
31
41
  * @param {String} ver - Version to check, for example '0.23.1'
42
+ * @param {function} fetch - HTTP call, defaults to sync-request
32
43
  * @return {Boolean} True if version exists, false otherwise
33
44
  */
34
- exists(ver) {
45
+ exists(ver, fetch = request) {
35
46
  let result;
36
47
  if (ver && ver !== 'undefined') {
37
48
  try {
38
- const repo = 'org/eolang/eo-maven-plugin',
39
- artifactId = 'eo-maven-plugin',
40
- url = `https://repo.maven.apache.org/maven2/${repo}/${ver}/${artifactId}-${ver}.pom`,
41
- res = request('GET', url, {timeout: 10000, socketTimeout: 10000});
49
+ const res = fetch('GET', version.url(ver), {timeout: 10000, socketTimeout: 10000});
42
50
  result = res.statusCode === 200;
43
51
  } catch (e) {
44
52
  console.debug('Unable to validate parser version (network error): %s', e.message);
package/src/version.js CHANGED
@@ -6,6 +6,6 @@
6
6
  // The values here are replaced automatically by the .rultor.yml script,
7
7
  // at the "release" pipeline:
8
8
  module.exports = {
9
- what: '0.35.1',
10
- when: '2026-04-23'
9
+ what: '0.35.2',
10
+ when: '2026-06-23'
11
11
  };
@@ -1,25 +0,0 @@
1
- # SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
2
- # SPDX-License-Identifier: MIT
3
- diff --git a/node_modules/grunt-mocha-cli/lib/index.js b/node_modules/grunt-mocha-cli/lib/index.js
4
- index 59f7a07..4cc7182 100644
5
- --- a/node_modules/grunt-mocha-cli/lib/index.js
6
- +++ b/node_modules/grunt-mocha-cli/lib/index.js
7
- @@ -2,6 +2,7 @@
8
- const fs = require('fs')
9
- const path = require('path')
10
- const grunt = require('grunt')
11
- +const os = require('os')
12
-
13
- const BOOL_OPTIONS = [
14
- 'allow-uncaught',
15
- @@ -55,6 +56,10 @@ module.exports = function(options) {
16
- spawnOptions.cmd = path.dirname(spawnOptions.cmd)
17
- spawnOptions.cmd += '/../.bin/mocha'
18
-
19
- + if (os.platform() === 'win32') {
20
- + spawnOptions.opts.shell = true
21
- + }
22
- +
23
- if (process.platform === 'win32') {
24
- spawnOptions.cmd += '.cmd'
25
- }
@@ -1,53 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /*
4
- * SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com
5
- * SPDX-License-Identifier: MIT
6
- */
7
-
8
- /**
9
- * Conditional postinstall script that only runs patch-package in development.
10
- * This prevents patch-package from running during production installs where
11
- * devDependencies (like grunt-mocha-cli) are not available.
12
- */
13
-
14
- const fs = require('fs');
15
- const path = require('path');
16
- const { spawn } = require('child_process');
17
-
18
- const gruntMochaCli = path.join(__dirname, '..', 'node_modules', 'grunt-mocha-cli');
19
-
20
- function findPatchPackage() {
21
- const binDir = path.join(__dirname, '..', 'node_modules', '.bin');
22
- if (process.platform === 'win32') {
23
- const cmdFile = path.join(binDir, 'patch-package.cmd');
24
- if (fs.existsSync(cmdFile)) {
25
- return cmdFile;
26
- }
27
- }
28
- const binFile = path.join(binDir, 'patch-package');
29
- if (fs.existsSync(binFile)) {
30
- return binFile;
31
- }
32
- return null;
33
- }
34
-
35
- const patchPackageBin = findPatchPackage();
36
-
37
- if (fs.existsSync(gruntMochaCli) && patchPackageBin) {
38
- console.log('Development environment detected, running patch-package...');
39
- const spawnOptions = {
40
- stdio: 'inherit',
41
- shell: process.platform === 'win32'
42
- };
43
- const child = spawn(patchPackageBin, [], spawnOptions);
44
- child.on('exit', (code) => {
45
- process.exit(code);
46
- });
47
- child.on('error', (err) => {
48
- console.error('Failed to execute patch-package:', err);
49
- process.exit(1);
50
- });
51
- } else {
52
- console.log('Production environment detected, skipping patch-package.');
53
- }