From c9f77e067ebdd1abcb2f7806a0790cbde8d08f75 Mon Sep 17 00:00:00 2001 From: Vladimir Paskhalov Date: Wed, 25 Mar 2026 13:46:01 +0200 Subject: [PATCH 1/6] feat(#857): readme-automation --- .github/workflows/readme-automation.yml | 44 +++++++++++++++ README.md | 3 ++ scripts/readme_automation/help_to_markdown.js | 53 +++++++++++++++++++ .../readme_automation_run.js | 29 ++++++++++ src/eoc.js | 18 ++++--- test/test_eoc.js | 7 +++ test/test_readme_automation.js | 34 ++++++++++++ 7 files changed, 182 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/readme-automation.yml create mode 100755 scripts/readme_automation/help_to_markdown.js create mode 100644 scripts/readme_automation/readme_automation_run.js create mode 100644 test/test_readme_automation.js diff --git a/.github/workflows/readme-automation.yml b/.github/workflows/readme-automation.yml new file mode 100644 index 00000000..4e899325 --- /dev/null +++ b/.github/workflows/readme-automation.yml @@ -0,0 +1,44 @@ +# SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +name: readme-automation + +'on': + workflow_dispatch: + push: + paths: + - "src/eoc.js" +concurrency: + group: readmeautomation-${{ github.ref }} + cancel-in-progress: true +jobs: + build: + runs-on: ubuntu-24.04 + + steps: + - name: Check out repo + uses: actions/checkout@v6 + - name: Use Node + uses: actions/setup-node@v6 + with: + node-version: "18.x" + check-latest: false + - name: Clean install + run: npm ci + - name: Install global + run: npm install -g + - name: Run readme_automation script + run: |- + node scripts/readme_automation/readme_automation_run.js + - name: Create Pull Request + uses: peter-evans/create-pull-request@v8 + with: + commit-message: "chore(readme): insert sections into README from CLI help" + branch: chore/readme-automation + title: "chore(readme): insert sections into README from CLI help" + body: | + This PR was automatically generated by GitHub Actions. + + - Insert sections into README from CLI help output + - Keeps documentation in sync with the CLI diff --git a/README.md b/README.md index 751862b9..42dcb87b 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ That's it. You can also do many other things with `eoc` commands (the flow is explained in [this blog post][blog]): + * `register` finds necessary `.eo` files and registers them in a JSON catalog * `assemble` parses `.eo` files into `.xmir`, optimizes them, and pulls foreign EO objects @@ -151,6 +152,8 @@ There are also commands that help manipulate with XMIR and EO sources * ~~`dejump` removes `goto` objects~~ * ~~`infer` suggests object names where it's possible to infer them~~ * ~~`flatten` moves inner objects to upper level~~ + + This command line toolkit simply integrates other tools available in the [@objectionary](https://github.com/objectionary) GitHub organization. diff --git a/scripts/readme_automation/help_to_markdown.js b/scripts/readme_automation/help_to_markdown.js new file mode 100755 index 00000000..09440814 --- /dev/null +++ b/scripts/readme_automation/help_to_markdown.js @@ -0,0 +1,53 @@ +#!/usr/bin/env node +/* + * SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com + * SPDX-License-Identifier: MIT + */ + +function escapeRegex(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +function updateSection(sectionName, newContent, readMeContent) { + const start = ``; + const end = ``; + const regex = new RegExp( + `(${escapeRegex(start)})([\\s\\S]*?)(${escapeRegex(end)})`, + "g" + ); + return readMeContent.replace(regex, `$1\n${newContent}\n$3`); +} + +function bulletListTemplate(rows) +{ + const list = rows.map(([cmd, desc]) => `* \`${cmd}\` ${desc}`); + return `${list.join("\n") }\n`; +} + +function parseBlock(block_name,text) { + const lines = text.split("\n"); + let inBlock = false; + const rows = []; + for (const line of lines) { + if (line.trim() === block_name) { + inBlock = true; + } + else if (inBlock) { + if (!line.trim()) {break;} + const parts = line.trim().split(/\s{2,}/); + const cmd = parts[0]; + const desc = parts.slice(1).join(" ") || ""; + rows.push([cmd, desc]); + } + } + if (!rows.length) + { + throw new Error('no data something wrong'); + } + return rows; +} + +module.exports = { + parseBlock, bulletListTemplate, updateSection +}; + diff --git a/scripts/readme_automation/readme_automation_run.js b/scripts/readme_automation/readme_automation_run.js new file mode 100644 index 00000000..21c26358 --- /dev/null +++ b/scripts/readme_automation/readme_automation_run.js @@ -0,0 +1,29 @@ +#!/usr/bin/env node +/* + * SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com + * SPDX-License-Identifier: MIT + */ + +const fs = require("fs"); +const assert = require('assert'); +const { parseBlock, bulletListTemplate, updateSection } = require("./help_to_markdown"); +const { getHelp } = require("../../src/eoc"); + +function main (){ + let help_text = getHelp(); + help_text = help_text.replace(/\r\n/g, "\n"); + assert.ok(["Options:","Commands:"].every(sub => help_text.includes(sub)),'"eoc --help" should includes Commands and Options'); + const commands = parseBlock('Commands:',help_text); + assert.ok(commands.length > 0,'Commands should have rows') + const commandsMarkdown = bulletListTemplate(commands); + assert.ok(commandsMarkdown.length > 0,"commandsMarkdown result should have text") + let readMeContent = fs.readFileSync('README.md', "utf8"); + assert.ok(readMeContent.length > 0,"readMeContent should have text") + readMeContent = updateSection('commands', commandsMarkdown, readMeContent); + assert.ok(readMeContent.length > 0,"readMeContent should sill have text after modification") + fs.writeFileSync('README.md',readMeContent); +} + +if (require.main === module) { + main(); +}; diff --git a/src/eoc.js b/src/eoc.js index 352be112..329ce900 100755 --- a/src/eoc.js +++ b/src/eoc.js @@ -394,12 +394,18 @@ program.command('fmt') }); }); -try { - program.parse(process.argv); -} catch (e) { - console.error(e.message); - console.debug(e.stack); - process.exit(1); +if (require.main === module) { + try { + program.parse(process.argv); + } catch (e) { + console.error(e.message); + console.debug(e.stack); + process.exit(1); + } +} + +module.exports.getHelp = function getHelp() { + return program.helpInformation(); } /** diff --git a/test/test_eoc.js b/test/test_eoc.js index ef403f9f..d2c62720 100644 --- a/test/test_eoc.js +++ b/test/test_eoc.js @@ -20,6 +20,13 @@ describe('eoc', () => { assert(stdout.includes(version.when)); done(); }); + it('can get help from eoc as a module', (done) => { + const output = require('../src/eoc').getHelp(); + assert(output.includes('Usage: eoc')); + assert(output.includes(version.what)); + assert(output.includes(version.when)); + done(); + }); }); describe('eoc', () => { diff --git a/test/test_readme_automation.js b/test/test_readme_automation.js new file mode 100644 index 00000000..b45e5501 --- /dev/null +++ b/test/test_readme_automation.js @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com + * SPDX-License-Identifier: MIT + */ + +const assert = require("assert"); +const path = require("path"); +const { parseBlock, updateSection, bulletListTemplate } = require(path.join(__dirname, "../scripts/readme_automation/help_to_markdown.js")); + +describe("readme_automation scripts", () => { + it("parseBlock builds a markdown table from a help block", () => { + const text = `\nUsage: eoc [options] [command]\nCommands:\n foo does foo\n bar does bar\n\nOptions:\n -h, --help output help`; + const res = parseBlock("Commands:", text); + assert.deepEqual(res,[['foo','does foo'],['bar','does bar']]); + const res2 = parseBlock("Options:", text); + assert.deepEqual(res2,[['-h, --help','output help']] ); + }); + it("parseBlock throws when no rows are found", () => { + assert.throws( + () => parseBlock("Commands:", ""), + /no data/ + ); + }); + it("updateSection replaces only the requested section", () => { + const readme = `before\n\nold\n\n\nkeep\n\nafter` + const updated = updateSection("commands", "new content", readme); + assert.ok(!updated.includes("old")); + assert.ok(["new content","keep","after","before",""].every(sub => updated.includes(sub))); + }); + it("bulletListTemplate renders a list", async () => { + const output = bulletListTemplate([['one','a'],['two','b'],['three','c']]); + assert.strictEqual(output, "* `one` a\n* `two` b\n* `three` c\n"); + }); +}); From 3e33d863f722f68974caaaeaf814f48480addb6a Mon Sep 17 00:00:00 2001 From: Vladimir Paskhalov Date: Wed, 25 Mar 2026 14:43:37 +0200 Subject: [PATCH 2/6] fix: no-multiple-blanks --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 42dcb87b..fc14ea86 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,6 @@ There are also commands that help manipulate with XMIR and EO sources * ~~`flatten` moves inner objects to upper level~~ - This command line toolkit simply integrates other tools available in the [@objectionary](https://github.com/objectionary) GitHub organization. From f2e4247fd81f54ee79f4ee9b43330d947d8cfca6 Mon Sep 17 00:00:00 2001 From: Vladimir Paskhalov Date: Thu, 26 Mar 2026 08:51:20 +0200 Subject: [PATCH 3/6] fix: indentation style --- scripts/readme_automation/help_to_markdown.js | 6 ++---- scripts/readme_automation/readme_automation_run.js | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/readme_automation/help_to_markdown.js b/scripts/readme_automation/help_to_markdown.js index 09440814..10aaca9f 100755 --- a/scripts/readme_automation/help_to_markdown.js +++ b/scripts/readme_automation/help_to_markdown.js @@ -18,8 +18,7 @@ function updateSection(sectionName, newContent, readMeContent) { return readMeContent.replace(regex, `$1\n${newContent}\n$3`); } -function bulletListTemplate(rows) -{ +function bulletListTemplate(rows) { const list = rows.map(([cmd, desc]) => `* \`${cmd}\` ${desc}`); return `${list.join("\n") }\n`; } @@ -40,8 +39,7 @@ function parseBlock(block_name,text) { rows.push([cmd, desc]); } } - if (!rows.length) - { + if (!rows.length) { throw new Error('no data something wrong'); } return rows; diff --git a/scripts/readme_automation/readme_automation_run.js b/scripts/readme_automation/readme_automation_run.js index 21c26358..c33eb7d0 100644 --- a/scripts/readme_automation/readme_automation_run.js +++ b/scripts/readme_automation/readme_automation_run.js @@ -9,7 +9,7 @@ const assert = require('assert'); const { parseBlock, bulletListTemplate, updateSection } = require("./help_to_markdown"); const { getHelp } = require("../../src/eoc"); -function main (){ +function main () { let help_text = getHelp(); help_text = help_text.replace(/\r\n/g, "\n"); assert.ok(["Options:","Commands:"].every(sub => help_text.includes(sub)),'"eoc --help" should includes Commands and Options'); From 67023a6ec8dcba73dbe4ed8e52c8646dc454411b Mon Sep 17 00:00:00 2001 From: Vladimir Paskhalov Date: Thu, 26 Mar 2026 09:19:12 +0200 Subject: [PATCH 4/6] fix: no newline within section --- scripts/readme_automation/help_to_markdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/readme_automation/help_to_markdown.js b/scripts/readme_automation/help_to_markdown.js index 10aaca9f..afc2302e 100755 --- a/scripts/readme_automation/help_to_markdown.js +++ b/scripts/readme_automation/help_to_markdown.js @@ -15,7 +15,7 @@ function updateSection(sectionName, newContent, readMeContent) { `(${escapeRegex(start)})([\\s\\S]*?)(${escapeRegex(end)})`, "g" ); - return readMeContent.replace(regex, `$1\n${newContent}\n$3`); + return readMeContent.replace(regex, `$1\n${newContent}$3`); } function bulletListTemplate(rows) { From a92dc18604260bde7ec1b9ebe820a5c3245c950d Mon Sep 17 00:00:00 2001 From: Vladimir Paskhalov Date: Wed, 22 Apr 2026 12:05:23 +0300 Subject: [PATCH 5/6] refactor: fixes after review --- .github/workflows/readme-automation.yml | 2 +- scripts/readme_automation.js | 50 ++++++++++++++++++ scripts/readme_automation/help_to_markdown.js | 51 ------------------- .../readme_automation_run.js | 29 ----------- src/eoc.js | 5 +- test/test_eoc.js | 11 ++-- test/test_readme_automation.js | 46 +++++++++-------- 7 files changed, 86 insertions(+), 108 deletions(-) create mode 100644 scripts/readme_automation.js delete mode 100755 scripts/readme_automation/help_to_markdown.js delete mode 100644 scripts/readme_automation/readme_automation_run.js diff --git a/.github/workflows/readme-automation.yml b/.github/workflows/readme-automation.yml index 4e899325..fa375529 100644 --- a/.github/workflows/readme-automation.yml +++ b/.github/workflows/readme-automation.yml @@ -30,7 +30,7 @@ jobs: run: npm install -g - name: Run readme_automation script run: |- - node scripts/readme_automation/readme_automation_run.js + node scripts/readme_automation.js - name: Create Pull Request uses: peter-evans/create-pull-request@v8 with: diff --git a/scripts/readme_automation.js b/scripts/readme_automation.js new file mode 100644 index 00000000..1970b1b9 --- /dev/null +++ b/scripts/readme_automation.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node +/* + * SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com + * SPDX-License-Identifier: MIT + */ + +const assert = require('assert'); +const { commandsDescription } = require("../src/eoc"); + +function escapeRegex(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +function updateSection(sectionName, newContent, readMeContent) { + const start = ``; + const end = ``; + const regex = new RegExp( + `(${escapeRegex(start)})([\\s\\S]*?)(${escapeRegex(end)})`, + "g" + ); + return readMeContent.replace(regex, `$1\n${newContent}$3`); +} + +function bulletListTemplate(rows) { + return `${rows.map(([cmd, desc]) => `* \`${cmd}\` ${desc}`).join("\n") }\n`; +} + +function modifyReadme(commands,fs) { + assert.ok(commands.length > 0,'Commands should have rows') + const commandsMarkdown = bulletListTemplate(commands); + assert.ok(commandsMarkdown.length > 0,"commandsMarkdown result should have text") + let readMeContent = fs.readFileSync('README.md', "utf8"); + assert.ok(readMeContent.length > 0,"readMeContent should have text") + readMeContent = updateSection('commands', commandsMarkdown, readMeContent); + assert.ok(readMeContent.length > 0,"readMeContent should sill have text after modification") + fs.writeFileSync('README.md',readMeContent); +} + +function syncCommandsToReadme(fs) +{ + modifyReadme(commandsDescription(),fs); +} + +module.exports = { + bulletListTemplate, updateSection, modifyReadme, syncCommandsToReadme +}; + +if (require.main === module) { + syncCommandsToReadme(require("fs")); +}; diff --git a/scripts/readme_automation/help_to_markdown.js b/scripts/readme_automation/help_to_markdown.js deleted file mode 100755 index afc2302e..00000000 --- a/scripts/readme_automation/help_to_markdown.js +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env node -/* - * SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com - * SPDX-License-Identifier: MIT - */ - -function escapeRegex(str) { - return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); -} - -function updateSection(sectionName, newContent, readMeContent) { - const start = ``; - const end = ``; - const regex = new RegExp( - `(${escapeRegex(start)})([\\s\\S]*?)(${escapeRegex(end)})`, - "g" - ); - return readMeContent.replace(regex, `$1\n${newContent}$3`); -} - -function bulletListTemplate(rows) { - const list = rows.map(([cmd, desc]) => `* \`${cmd}\` ${desc}`); - return `${list.join("\n") }\n`; -} - -function parseBlock(block_name,text) { - const lines = text.split("\n"); - let inBlock = false; - const rows = []; - for (const line of lines) { - if (line.trim() === block_name) { - inBlock = true; - } - else if (inBlock) { - if (!line.trim()) {break;} - const parts = line.trim().split(/\s{2,}/); - const cmd = parts[0]; - const desc = parts.slice(1).join(" ") || ""; - rows.push([cmd, desc]); - } - } - if (!rows.length) { - throw new Error('no data something wrong'); - } - return rows; -} - -module.exports = { - parseBlock, bulletListTemplate, updateSection -}; - diff --git a/scripts/readme_automation/readme_automation_run.js b/scripts/readme_automation/readme_automation_run.js deleted file mode 100644 index c33eb7d0..00000000 --- a/scripts/readme_automation/readme_automation_run.js +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env node -/* - * SPDX-FileCopyrightText: Copyright (c) 2022-2026 Objectionary.com - * SPDX-License-Identifier: MIT - */ - -const fs = require("fs"); -const assert = require('assert'); -const { parseBlock, bulletListTemplate, updateSection } = require("./help_to_markdown"); -const { getHelp } = require("../../src/eoc"); - -function main () { - let help_text = getHelp(); - help_text = help_text.replace(/\r\n/g, "\n"); - assert.ok(["Options:","Commands:"].every(sub => help_text.includes(sub)),'"eoc --help" should includes Commands and Options'); - const commands = parseBlock('Commands:',help_text); - assert.ok(commands.length > 0,'Commands should have rows') - const commandsMarkdown = bulletListTemplate(commands); - assert.ok(commandsMarkdown.length > 0,"commandsMarkdown result should have text") - let readMeContent = fs.readFileSync('README.md', "utf8"); - assert.ok(readMeContent.length > 0,"readMeContent should have text") - readMeContent = updateSection('commands', commandsMarkdown, readMeContent); - assert.ok(readMeContent.length > 0,"readMeContent should sill have text after modification") - fs.writeFileSync('README.md',readMeContent); -} - -if (require.main === module) { - main(); -}; diff --git a/src/eoc.js b/src/eoc.js index 329ce900..1a15cbbd 100755 --- a/src/eoc.js +++ b/src/eoc.js @@ -404,8 +404,9 @@ if (require.main === module) { } } -module.exports.getHelp = function getHelp() { - return program.helpInformation(); +module.exports.commandsDescription = function commandsDescription() { + return program.commands + .map(c => [c.name(),c.description()]); } /** diff --git a/test/test_eoc.js b/test/test_eoc.js index d2c62720..cbc449c1 100644 --- a/test/test_eoc.js +++ b/test/test_eoc.js @@ -20,11 +20,12 @@ describe('eoc', () => { assert(stdout.includes(version.when)); done(); }); - it('can get help from eoc as a module', (done) => { - const output = require('../src/eoc').getHelp(); - assert(output.includes('Usage: eoc')); - assert(output.includes(version.what)); - assert(output.includes(version.when)); + it('can get commands description from eoc as a module', (done) => { + const commandsDescriptionList = require('../src/eoc').commandsDescription(); + assert(commandsDescriptionList.length > 0,"commandsDescriptionList should have more then one element"); + assert(commandsDescriptionList[0].length == 2,"commandsDescriptionList element should have 2 values"); + assert(commandsDescriptionList[0][0].length > 0,"First value of commandsDescriptionList element should have non-zero length"); + assert(commandsDescriptionList[0][1].length > 0,"Second value of commandsDescriptionList element should have non-zero length"); done(); }); }); diff --git a/test/test_readme_automation.js b/test/test_readme_automation.js index b45e5501..dcac222d 100644 --- a/test/test_readme_automation.js +++ b/test/test_readme_automation.js @@ -5,30 +5,36 @@ const assert = require("assert"); const path = require("path"); -const { parseBlock, updateSection, bulletListTemplate } = require(path.join(__dirname, "../scripts/readme_automation/help_to_markdown.js")); +const { updateSection, bulletListTemplate, modifyReadme, syncCommandsToReadme} = require(path.join(__dirname, "../scripts/readme_automation.js")); + +const readme = `before\n\nold content\n\n\nkeep\n\nafter` +const commandsList = [['one','a'],['two','b'],['three','c']]; +const keywords = ["keep","after","before","",""]; +const fsMockProto = {readMeContent:null, readFileSync(path,options){ return readme; }, writeFileSync(path,data){ this.readMeContent = data; }}; + describe("readme_automation scripts", () => { - it("parseBlock builds a markdown table from a help block", () => { - const text = `\nUsage: eoc [options] [command]\nCommands:\n foo does foo\n bar does bar\n\nOptions:\n -h, --help output help`; - const res = parseBlock("Commands:", text); - assert.deepEqual(res,[['foo','does foo'],['bar','does bar']]); - const res2 = parseBlock("Options:", text); - assert.deepEqual(res2,[['-h, --help','output help']] ); - }); - it("parseBlock throws when no rows are found", () => { - assert.throws( - () => parseBlock("Commands:", ""), - /no data/ - ); - }); it("updateSection replaces only the requested section", () => { - const readme = `before\n\nold\n\n\nkeep\n\nafter` - const updated = updateSection("commands", "new content", readme); - assert.ok(!updated.includes("old")); - assert.ok(["new content","keep","after","before",""].every(sub => updated.includes(sub))); + const readmeUpdated = updateSection("commands", "new content", readme); + assert.ok(!readmeUpdated.includes("old content"),"Update README should no have 'old content'"); + assert.ok(keywords.every(sub => readmeUpdated.includes(sub)),"Update README should have all keywords"); + assert.ok(readmeUpdated.includes("new content"),"Update README should have `new content`"); }); it("bulletListTemplate renders a list", async () => { - const output = bulletListTemplate([['one','a'],['two','b'],['three','c']]); - assert.strictEqual(output, "* `one` a\n* `two` b\n* `three` c\n"); + const bulletListMarkdown = bulletListTemplate(commandsList); + assert.strictEqual(bulletListMarkdown, "* `one` a\n* `two` b\n* `three` c\n"); + }); + it("call modifyReadme with fs mock", async () => { + const fsMock = {...fsMockProto}; + modifyReadme(commandsList,fsMock); + assert.notEqual(fsMock.readMeContent,null,"README file should have some content"); + assert.ok(!fsMock.readMeContent.includes("old content"),"README file should no have 'old content'"); + assert.ok(keywords.every(sub => fsMock.readMeContent.includes(sub)),"README file should have all keywords"); + assert.ok(["* `one` a","* `two` b","* `three` c"].every(sub => fsMock.readMeContent.includes(sub))); + }); + it("test the whole workflow with fs mock", async () => { + const fsMock = {...fsMockProto}; + syncCommandsToReadme(fsMock); + assert.notEqual(fsMock.readMeContent,null,"README file should have some content"); }); }); From 355aa91433755255c6ed12fc921de1ed7c416740 Mon Sep 17 00:00:00 2001 From: paskhalov <46865041+paskhalov@users.noreply.github.com> Date: Wed, 22 Apr 2026 09:06:36 +0000 Subject: [PATCH 6/6] chore(readme): insert sections into README from CLI help --- README.md | 58 +++++++++++++++++++++---------------------------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index fc14ea86..07b41012 100644 --- a/README.md +++ b/README.md @@ -116,42 +116,28 @@ You can also do many other things with `eoc` commands (the flow is explained in [this blog post][blog]): -* `register` finds necessary `.eo` files and registers them in a JSON catalog -* `assemble` parses `.eo` files into `.xmir`, optimizes them, - and pulls foreign EO objects -* `transpile` converts `.xmir` files to the target programming -language (Java by default) -* `compile` converts target language sources (e.g., `.java`) -to binaries (e.g., `.class`) -* `link` puts all binaries together into a single executable binary -* `dataize` dataizes a single object from the executable binary -* `test` dataizes all visible unit tests -* `lint` finds style-related errors in EO and XMIR files -* `jeo:disassemble` converts Java `.class` files to `.xmir` -(via [jeo](https://github.com/objectionary/jeo-maven-plugin)) -* `jeo:assemble` converts `.xmir` files to Java `.class` files -(via [jeo](https://github.com/objectionary/jeo-maven-plugin)) - -There are also commands that help manipulate with XMIR and EO sources -(the list is not completed, while some of them are not implemented as of yet): - -* `audit` inspects all required packages and reports their status -* `foreign` inspects all objects found in the program after the `assemble` step -* `sodg` generates `.sodg` from `.xmir`, further rederable as XML or [Dot][dot] -* `print` generates `.eo` files from `.xmir` files -* `generate_comments` generates `.json` files with LLM-generated - documentation for `.eo` structures -* `docs` generates HTML documentation from `.xmir` files -* `latex` generates `.tex` files from `.eo` sources -* `fmt` formats `.eo` files in the source directory -* `normalize` normalizes `.eo` files via phi-calculus rewriting using - [phino](https://github.com/objectionary/phino) (must be installed separately); - original files are saved to `.eoc/before-normalize/` for debugging -* ~~`translate` converts Java/C++/Python/etc. program to EO program~~ -* ~~`demu` removes `cage` and `memory` objects~~ -* ~~`dejump` removes `goto` objects~~ -* ~~`infer` suggests object names where it's possible to infer them~~ -* ~~`flatten` moves inner objects to upper level~~ +* `audit` Inspect all packages and report their status +* `foreign` Inspect and print the list of foreign objects +* `clean` Delete all temporary files +* `register` Register all visible EO source files +* `parse` Parse EO files into XMIR +* `assemble` Parse EO files into XMIR and join them with required dependencies +* `sodg` Generate SODG files from XMIR +* `print` Generate EO files from XMIR files +* `lint` Lint XMIR files and fail if any issues inside +* `resolve` Resolve all the dependencies required for compilation +* `transpile` Convert EO files into target language +* `compile` Compile target language sources into binaries +* `link` Link together all binaries into a single executable binary +* `dataize` Run the single executable binary and dataize an object +* `test` Run all visible unit tests +* `docs` Generate documentation from XMIR files +* `generate_comments` Generate documentation with LLM +* `jeo:disassemble` Disassemble .class files to .xmir files +* `jeo:assemble` Assemble .xmir files to .class files +* `latex` Generate LaTeX files from EO sources +* `normalize` Normalize EO files using phi-calculus normalization via phino +* `fmt` Format EO files in the source directory This command line toolkit simply integrates other tools available in