@jotx-labs/cli 2.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.md ADDED
@@ -0,0 +1,155 @@
1
+ # @jotx/cli
2
+
3
+ Command-line interface for jotx - demonstrates platform independence.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @jotx/cli
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Parse a file
14
+
15
+ ```bash
16
+ jotx parse notes.jot
17
+ ```
18
+
19
+ Shows the AST (Abstract Syntax Tree) of the document.
20
+
21
+ ### Validate a file
22
+
23
+ ```bash
24
+ jotx validate notes.jot
25
+ ```
26
+
27
+ Checks if the file is valid jotx syntax.
28
+
29
+ ### Convert to HTML
30
+
31
+ ```bash
32
+ # Output to stdout
33
+ jotx convert notes.jot
34
+
35
+ # Output to file
36
+ jotx convert notes.jot -o notes.html
37
+ ```
38
+
39
+ Converts a `.jot` file to HTML.
40
+
41
+ ### Show info
42
+
43
+ ```bash
44
+ jotx info notes.jot
45
+ ```
46
+
47
+ Shows document metadata and statistics.
48
+
49
+ ## Examples
50
+
51
+ ```bash
52
+ # Validate all .jot files in current directory
53
+ for file in *.jot; do jotx validate "$file"; done
54
+
55
+ # Convert all .jot files to HTML
56
+ for file in *.jot; do jotx convert "$file" -o "${file%.jot}.html"; done
57
+
58
+ # Parse and pretty-print
59
+ jotx parse notes.jot | jq .
60
+ ```
61
+
62
+ ## Architecture
63
+
64
+ The CLI demonstrates jotx's platform independence:
65
+
66
+ - Uses `@jotx/core` for parsing/validation
67
+ - Uses `NodePlatform` from `@jotx/adapters` for file I/O
68
+ - Uses `HTMLRenderer` from `@jotx/adapters` for output
69
+ - **Zero** VS Code dependencies
70
+ - **Zero** browser dependencies
71
+
72
+ Same core logic, different platform!
73
+
74
+ ## Development
75
+
76
+ ```bash
77
+ # Build
78
+ npm run build
79
+
80
+ # Test locally
81
+ node dist/cli.js parse test.jot
82
+ ```
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+
132
+
133
+
134
+
135
+
136
+
137
+
138
+
139
+
140
+
141
+
142
+
143
+
144
+
145
+
146
+
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+
155
+
package/dist/cli.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * jotx CLI - Demonstrates platform independence
4
+ * Uses @jotx/core + NodePlatform
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;GAGG"}
package/dist/cli.js ADDED
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * jotx CLI - Demonstrates platform independence
5
+ * Uses @jotx/core + NodePlatform
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ const commander_1 = require("commander");
42
+ const fs = __importStar(require("fs/promises"));
43
+ const program = new commander_1.Command();
44
+ program
45
+ .name('jotx')
46
+ .description('jotx CLI - Parse, validate, and convert jotx files')
47
+ .version('1.0.22');
48
+ // Parse command
49
+ program
50
+ .command('parse <file>')
51
+ .description('Parse a .jot file and show AST')
52
+ .action(async (file) => {
53
+ try {
54
+ const text = await fs.readFile(file, 'utf-8');
55
+ const result = core.parseAndValidate(text);
56
+ if (result.isValid) {
57
+ console.log('✅ Parse successful!');
58
+ console.log(JSON.stringify(result.ast, null, 2));
59
+ }
60
+ else {
61
+ console.error('❌ Parse failed:');
62
+ result.validation.errors.forEach(err => {
63
+ console.error(` - ${err.message}`);
64
+ });
65
+ process.exit(1);
66
+ }
67
+ }
68
+ catch (error) {
69
+ console.error('❌ Error:', error);
70
+ process.exit(1);
71
+ }
72
+ });
73
+ // Validate command
74
+ program
75
+ .command('validate <file>')
76
+ .description('Validate a .jot file')
77
+ .action(async (file) => {
78
+ try {
79
+ const text = await fs.readFile(file, 'utf-8');
80
+ const result = core.parseAndValidate(text);
81
+ if (result.isValid) {
82
+ console.log(`✅ ${file} is valid!`);
83
+ console.log(` Document: ${result.ast.document.id}`);
84
+ console.log(` Type: ${result.ast.document.documentType}`);
85
+ console.log(` Blocks: ${result.ast.document.blocks.length}`);
86
+ }
87
+ else {
88
+ console.error(`❌ ${file} has errors:`);
89
+ result.validation.errors.forEach(err => {
90
+ console.error(` - ${err.message}`);
91
+ });
92
+ process.exit(1);
93
+ }
94
+ }
95
+ catch (error) {
96
+ console.error('❌ Error:', error);
97
+ process.exit(1);
98
+ }
99
+ });
100
+ // Convert command
101
+ program
102
+ .command('convert <file>')
103
+ .description('Convert .jot file to HTML')
104
+ .option('-o, --output <file>', 'Output file (default: stdout)')
105
+ .action(async (file, options) => {
106
+ try {
107
+ const text = await fs.readFile(file, 'utf-8');
108
+ const result = core.parseAndValidate(text);
109
+ if (!result.isValid) {
110
+ console.error('❌ File has errors:');
111
+ result.validation.errors.forEach(err => {
112
+ console.error(` - ${err.message}`);
113
+ });
114
+ process.exit(1);
115
+ }
116
+ // Render to HTML
117
+ const html = renderer.render({
118
+ id: result.ast.document.id,
119
+ type: result.ast.document.documentType,
120
+ metadata: result.ast.document.metadata,
121
+ blocks: result.ast.document.blocks
122
+ });
123
+ // Wrap in full HTML document
124
+ const fullHtml = `<!DOCTYPE html>
125
+ <html lang="en">
126
+ <head>
127
+ <meta charset="UTF-8">
128
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
129
+ <title>${result.ast.document.metadata.title || 'jotx Document'}</title>
130
+ <style>
131
+ body { font-family: system-ui, -apple-system, sans-serif; max-width: 800px; margin: 40px auto; padding: 0 20px; }
132
+ h1 { font-size: 2em; margin-bottom: 0.5em; }
133
+ h2 { font-size: 1.5em; margin-top: 1.5em; }
134
+ h3 { font-size: 1.2em; margin-top: 1.2em; }
135
+ code { background: #f5f5f5; padding: 2px 6px; border-radius: 3px; }
136
+ pre { background: #f5f5f5; padding: 16px; border-radius: 6px; overflow-x: auto; }
137
+ blockquote { border-left: 4px solid #ddd; padding-left: 16px; margin-left: 0; color: #666; }
138
+ </style>
139
+ </head>
140
+ <body>
141
+ ${html}
142
+ </body>
143
+ </html>`;
144
+ if (options.output) {
145
+ await fs.writeFile(options.output, fullHtml, 'utf-8');
146
+ console.log(`✅ Converted to ${options.output}`);
147
+ }
148
+ else {
149
+ console.log(fullHtml);
150
+ }
151
+ }
152
+ catch (error) {
153
+ console.error('❌ Error:', error);
154
+ process.exit(1);
155
+ }
156
+ });
157
+ // Info command
158
+ program
159
+ .command('info <file>')
160
+ .description('Show document information')
161
+ .action(async (file) => {
162
+ try {
163
+ const text = await fs.readFile(file, 'utf-8');
164
+ const result = core.parseAndValidate(text);
165
+ if (!result.isValid) {
166
+ console.error('❌ File has errors');
167
+ process.exit(1);
168
+ }
169
+ const doc = result.ast.document;
170
+ console.log('📄 Document Information');
171
+ console.log('─'.repeat(50));
172
+ console.log(`ID: ${doc.id}`);
173
+ console.log(`Type: ${doc.documentType}`);
174
+ console.log(`Title: ${doc.metadata.title || '(none)'}`);
175
+ console.log(`Blocks: ${doc.blocks.length}`);
176
+ console.log();
177
+ console.log('Block Types:');
178
+ const blockCounts = {};
179
+ doc.blocks.forEach(block => {
180
+ blockCounts[block.type] = (blockCounts[block.type] || 0) + 1;
181
+ });
182
+ Object.entries(blockCounts).forEach(([type, count]) => {
183
+ console.log(` - ${type}: ${count}`);
184
+ });
185
+ }
186
+ catch (error) {
187
+ console.error('❌ Error:', error);
188
+ process.exit(1);
189
+ }
190
+ });
191
+ program.parse();
192
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@jotx-labs/cli",
3
+ "version": "2.2.1",
4
+ "description": "jotx command-line interface",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "jotx": "./dist/cli.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "test": "jest",
12
+ "clean": "rm -rf dist"
13
+ },
14
+ "keywords": [
15
+ "jotx",
16
+ "cli",
17
+ "notes",
18
+ "parser"
19
+ ],
20
+ "author": "jotx",
21
+ "license": "Apache-2.0",
22
+ "dependencies": {
23
+ "@jotx/core": "file:../core",
24
+ "@jotx/adapters": "file:../adapters",
25
+ "commander": "^11.0.0",
26
+ "chalk": "^4.1.2"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^20.0.0",
30
+ "typescript": "^5.0.0"
31
+ }
32
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * jotx CLI - Demonstrates platform independence
4
+ * Uses @jotx/core + NodePlatform
5
+ */
6
+
7
+ import { Command } from 'commander'
8
+ import * as fs from 'fs/promises'
9
+ import * as path from 'path'
10
+ import { jotToMarkdown, markdownToJot } from '@jotx-labs/core'
11
+
12
+ const program = new Command()
13
+
14
+ program
15
+ .name('jotx')
16
+ .description('jotx CLI - Parse, validate, and convert jotx files')
17
+ .version('1.0.22')
18
+
19
+ // Parse command
20
+ program
21
+ .command('parse <file>')
22
+ .description('Parse a .jot file and show AST')
23
+ .action(async (file: string) => {
24
+ try {
25
+ const text = await fs.readFile(file, 'utf-8')
26
+ const result = core.parseAndValidate(text)
27
+
28
+ if (result.isValid) {
29
+ console.log('✅ Parse successful!')
30
+ console.log(JSON.stringify(result.ast, null, 2))
31
+ } else {
32
+ console.error('❌ Parse failed:')
33
+ result.validation.errors.forEach(err => {
34
+ console.error(` - ${err.message}`)
35
+ })
36
+ process.exit(1)
37
+ }
38
+ } catch (error) {
39
+ console.error('❌ Error:', error)
40
+ process.exit(1)
41
+ }
42
+ })
43
+
44
+ // Validate command
45
+ program
46
+ .command('validate <file>')
47
+ .description('Validate a .jot file')
48
+ .action(async (file: string) => {
49
+ try {
50
+ const text = await fs.readFile(file, 'utf-8')
51
+ const result = core.parseAndValidate(text)
52
+
53
+ if (result.isValid) {
54
+ console.log(`✅ ${file} is valid!`)
55
+ console.log(` Document: ${result.ast.document.id}`)
56
+ console.log(` Type: ${result.ast.document.documentType}`)
57
+ console.log(` Blocks: ${result.ast.document.blocks.length}`)
58
+ } else {
59
+ console.error(`❌ ${file} has errors:`)
60
+ result.validation.errors.forEach(err => {
61
+ console.error(` - ${err.message}`)
62
+ })
63
+ process.exit(1)
64
+ }
65
+ } catch (error) {
66
+ console.error('❌ Error:', error)
67
+ process.exit(1)
68
+ }
69
+ })
70
+
71
+ // Convert command
72
+ program
73
+ .command('convert <file>')
74
+ .description('Convert .jot file to HTML')
75
+ .option('-o, --output <file>', 'Output file (default: stdout)')
76
+ .action(async (file: string, options: { output?: string }) => {
77
+ try {
78
+ const text = await fs.readFile(file, 'utf-8')
79
+ const result = core.parseAndValidate(text)
80
+
81
+ if (!result.isValid) {
82
+ console.error('❌ File has errors:')
83
+ result.validation.errors.forEach(err => {
84
+ console.error(` - ${err.message}`)
85
+ })
86
+ process.exit(1)
87
+ }
88
+
89
+ // Render to HTML
90
+ const html = renderer.render({
91
+ id: result.ast.document.id,
92
+ type: result.ast.document.documentType,
93
+ metadata: result.ast.document.metadata,
94
+ blocks: result.ast.document.blocks as any
95
+ } as any)
96
+
97
+ // Wrap in full HTML document
98
+ const fullHtml = `<!DOCTYPE html>
99
+ <html lang="en">
100
+ <head>
101
+ <meta charset="UTF-8">
102
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
103
+ <title>${result.ast.document.metadata.title || 'jotx Document'}</title>
104
+ <style>
105
+ body { font-family: system-ui, -apple-system, sans-serif; max-width: 800px; margin: 40px auto; padding: 0 20px; }
106
+ h1 { font-size: 2em; margin-bottom: 0.5em; }
107
+ h2 { font-size: 1.5em; margin-top: 1.5em; }
108
+ h3 { font-size: 1.2em; margin-top: 1.2em; }
109
+ code { background: #f5f5f5; padding: 2px 6px; border-radius: 3px; }
110
+ pre { background: #f5f5f5; padding: 16px; border-radius: 6px; overflow-x: auto; }
111
+ blockquote { border-left: 4px solid #ddd; padding-left: 16px; margin-left: 0; color: #666; }
112
+ </style>
113
+ </head>
114
+ <body>
115
+ ${html}
116
+ </body>
117
+ </html>`
118
+
119
+ if (options.output) {
120
+ await fs.writeFile(options.output, fullHtml, 'utf-8')
121
+ console.log(`✅ Converted to ${options.output}`)
122
+ } else {
123
+ console.log(fullHtml)
124
+ }
125
+ } catch (error) {
126
+ console.error('❌ Error:', error)
127
+ process.exit(1)
128
+ }
129
+ })
130
+
131
+ // Info command
132
+ program
133
+ .command('info <file>')
134
+ .description('Show document information')
135
+ .action(async (file: string) => {
136
+ try {
137
+ const text = await fs.readFile(file, 'utf-8')
138
+ const result = core.parseAndValidate(text)
139
+
140
+ if (!result.isValid) {
141
+ console.error('❌ File has errors')
142
+ process.exit(1)
143
+ }
144
+
145
+ const doc = result.ast.document
146
+
147
+ console.log('📄 Document Information')
148
+ console.log('─'.repeat(50))
149
+ console.log(`ID: ${doc.id}`)
150
+ console.log(`Type: ${doc.documentType}`)
151
+ console.log(`Title: ${doc.metadata.title || '(none)'}`)
152
+ console.log(`Blocks: ${doc.blocks.length}`)
153
+ console.log()
154
+ console.log('Block Types:')
155
+
156
+ const blockCounts: Record<string, number> = {}
157
+ doc.blocks.forEach(block => {
158
+ blockCounts[block.type] = (blockCounts[block.type] || 0) + 1
159
+ })
160
+
161
+ Object.entries(blockCounts).forEach(([type, count]) => {
162
+ console.log(` - ${type}: ${count}`)
163
+ })
164
+ } catch (error) {
165
+ console.error('❌ Error:', error)
166
+ process.exit(1)
167
+ }
168
+ })
169
+
170
+ program.parse()
171
+
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "resolveJsonModule": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true
15
+ },
16
+ "include": ["src/**/*.ts"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }
19
+