@diagrammo/dgmo 0.1.0 → 0.1.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 +41 -0
- package/dist/cli.cjs +85 -30
- package/package.json +3 -2
- package/src/cli.ts +100 -35
package/README.md
CHANGED
|
@@ -6,12 +6,53 @@ Write simple, readable `.dgmo` text files and render them as charts, diagrams, a
|
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
+
### As a library
|
|
10
|
+
|
|
9
11
|
```bash
|
|
10
12
|
npm install @diagrammo/dgmo
|
|
11
13
|
# or
|
|
12
14
|
pnpm add @diagrammo/dgmo
|
|
13
15
|
```
|
|
14
16
|
|
|
17
|
+
### As a CLI
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# via Homebrew (macOS)
|
|
21
|
+
brew tap diagrammo/dgmo
|
|
22
|
+
brew install dgmo
|
|
23
|
+
|
|
24
|
+
# or run directly via npx
|
|
25
|
+
npx @diagrammo/dgmo diagram.dgmo
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## CLI usage
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# First time with no args? Creates a sample.dgmo to get you started
|
|
32
|
+
dgmo
|
|
33
|
+
|
|
34
|
+
# Render to PNG (default)
|
|
35
|
+
dgmo diagram.dgmo # → diagram.png
|
|
36
|
+
|
|
37
|
+
# Render to SVG
|
|
38
|
+
dgmo diagram.dgmo -o output.svg
|
|
39
|
+
|
|
40
|
+
# Explicit PNG
|
|
41
|
+
dgmo diagram.dgmo -o output.png
|
|
42
|
+
|
|
43
|
+
# Pipe from stdin
|
|
44
|
+
cat diagram.dgmo | dgmo -o out.png
|
|
45
|
+
cat diagram.dgmo | dgmo > out.png # PNG to stdout
|
|
46
|
+
|
|
47
|
+
# With theme and palette options
|
|
48
|
+
dgmo diagram.dgmo --theme dark --palette catppuccin
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Option | Values | Default |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `--theme` | `light`, `dark`, `transparent` | `light` |
|
|
54
|
+
| `--palette` | `nord`, `solarized`, `catppuccin`, `rose-pine`, `gruvbox`, `tokyo-night`, `one-dark`, `bold` | `nord` |
|
|
55
|
+
|
|
15
56
|
## How it works
|
|
16
57
|
|
|
17
58
|
Every `.dgmo` file is plain text with a `chart: <type>` header followed by metadata and data. The library routes each chart type to the right framework and gives you either:
|
package/dist/cli.cjs
CHANGED
|
@@ -2459,6 +2459,7 @@ var init_renderer = __esm({
|
|
|
2459
2459
|
var import_node_fs = require("fs");
|
|
2460
2460
|
var import_node_path = require("path");
|
|
2461
2461
|
var import_jsdom = require("jsdom");
|
|
2462
|
+
var import_resvg_js = require("@resvg/resvg-js");
|
|
2462
2463
|
|
|
2463
2464
|
// src/d3.ts
|
|
2464
2465
|
var d3Scale = __toESM(require("d3-scale"), 1);
|
|
@@ -5056,13 +5057,15 @@ var PALETTES = [
|
|
|
5056
5057
|
];
|
|
5057
5058
|
var THEMES = ["light", "dark", "transparent"];
|
|
5058
5059
|
function printHelp() {
|
|
5059
|
-
console.log(`Usage: dgmo
|
|
5060
|
+
console.log(`Usage: dgmo <input> [options]
|
|
5061
|
+
cat input.dgmo | dgmo [options]
|
|
5060
5062
|
|
|
5061
|
-
|
|
5062
|
-
render <input> Render a .dgmo file to SVG
|
|
5063
|
+
Render a .dgmo file to PNG (default) or SVG.
|
|
5063
5064
|
|
|
5064
5065
|
Options:
|
|
5065
|
-
-o <file>
|
|
5066
|
+
-o <file> Output file (default: <input>.png in cwd)
|
|
5067
|
+
Format inferred from extension: .svg \u2192 SVG, else PNG
|
|
5068
|
+
With stdin and no -o, PNG is written to stdout
|
|
5066
5069
|
--theme <theme> Theme: ${THEMES.join(", ")} (default: light)
|
|
5067
5070
|
--palette <name> Palette: ${PALETTES.join(", ")} (default: nord)
|
|
5068
5071
|
--help Show this help
|
|
@@ -5076,7 +5079,6 @@ function printVersion() {
|
|
|
5076
5079
|
}
|
|
5077
5080
|
function parseArgs(argv) {
|
|
5078
5081
|
const result = {
|
|
5079
|
-
command: void 0,
|
|
5080
5082
|
input: void 0,
|
|
5081
5083
|
output: void 0,
|
|
5082
5084
|
theme: "light",
|
|
@@ -5117,9 +5119,6 @@ function parseArgs(argv) {
|
|
|
5117
5119
|
}
|
|
5118
5120
|
result.palette = val;
|
|
5119
5121
|
i++;
|
|
5120
|
-
} else if (!result.command) {
|
|
5121
|
-
result.command = arg;
|
|
5122
|
-
i++;
|
|
5123
5122
|
} else if (!result.input) {
|
|
5124
5123
|
result.input = arg;
|
|
5125
5124
|
i++;
|
|
@@ -5139,6 +5138,52 @@ function setupDom() {
|
|
|
5139
5138
|
Object.defineProperty(globalThis, "HTMLElement", { value: win.HTMLElement, configurable: true });
|
|
5140
5139
|
Object.defineProperty(globalThis, "SVGElement", { value: win.SVGElement, configurable: true });
|
|
5141
5140
|
}
|
|
5141
|
+
function inferFormat(outputPath) {
|
|
5142
|
+
if (outputPath && (0, import_node_path.extname)(outputPath).toLowerCase() === ".svg") {
|
|
5143
|
+
return "svg";
|
|
5144
|
+
}
|
|
5145
|
+
return "png";
|
|
5146
|
+
}
|
|
5147
|
+
function svgToPng(svg) {
|
|
5148
|
+
const resvg = new import_resvg_js.Resvg(svg, {
|
|
5149
|
+
fitTo: { mode: "zoom", value: 2 }
|
|
5150
|
+
});
|
|
5151
|
+
const rendered = resvg.render();
|
|
5152
|
+
return rendered.asPng();
|
|
5153
|
+
}
|
|
5154
|
+
function noInput() {
|
|
5155
|
+
const samplePath = (0, import_node_path.resolve)("sample.dgmo");
|
|
5156
|
+
if ((0, import_node_fs.existsSync)(samplePath)) {
|
|
5157
|
+
console.error("Error: No input file specified");
|
|
5158
|
+
console.error(`Try: dgmo ${(0, import_node_path.basename)(samplePath)}`);
|
|
5159
|
+
process.exit(1);
|
|
5160
|
+
}
|
|
5161
|
+
(0, import_node_fs.writeFileSync)(
|
|
5162
|
+
samplePath,
|
|
5163
|
+
[
|
|
5164
|
+
"chart: sequence",
|
|
5165
|
+
"activations: off",
|
|
5166
|
+
"",
|
|
5167
|
+
" Client -> API: POST /login",
|
|
5168
|
+
" API -> Auth: validate credentials",
|
|
5169
|
+
" Auth -> DB: SELECT user",
|
|
5170
|
+
" DB -> Auth: user record",
|
|
5171
|
+
" Auth -> API: JWT token",
|
|
5172
|
+
" API -> Client: 200 OK { token }",
|
|
5173
|
+
""
|
|
5174
|
+
].join("\n"),
|
|
5175
|
+
"utf-8"
|
|
5176
|
+
);
|
|
5177
|
+
console.error(`Created ${samplePath}`);
|
|
5178
|
+
console.error("");
|
|
5179
|
+
console.error(" Render it: dgmo sample.dgmo");
|
|
5180
|
+
console.error(" As SVG: dgmo sample.dgmo -o sample.svg");
|
|
5181
|
+
console.error("");
|
|
5182
|
+
console.error(
|
|
5183
|
+
"Edit sample.dgmo to make it your own, or run dgmo --help for all options."
|
|
5184
|
+
);
|
|
5185
|
+
process.exit(0);
|
|
5186
|
+
}
|
|
5142
5187
|
async function main() {
|
|
5143
5188
|
const opts = parseArgs(process.argv);
|
|
5144
5189
|
if (opts.help) {
|
|
@@ -5149,27 +5194,28 @@ async function main() {
|
|
|
5149
5194
|
printVersion();
|
|
5150
5195
|
return;
|
|
5151
5196
|
}
|
|
5152
|
-
if (opts.command !== "render") {
|
|
5153
|
-
if (opts.command) {
|
|
5154
|
-
console.error(`Error: Unknown command "${opts.command}"`);
|
|
5155
|
-
} else {
|
|
5156
|
-
console.error("Error: No command specified");
|
|
5157
|
-
}
|
|
5158
|
-
console.error('Run "dgmo --help" for usage');
|
|
5159
|
-
process.exit(1);
|
|
5160
|
-
}
|
|
5161
|
-
if (!opts.input) {
|
|
5162
|
-
console.error("Error: No input file specified");
|
|
5163
|
-
console.error("Usage: dgmo render <input> [-o output.svg]");
|
|
5164
|
-
process.exit(1);
|
|
5165
|
-
}
|
|
5166
|
-
const inputPath = (0, import_node_path.resolve)(opts.input);
|
|
5167
5197
|
let content;
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5198
|
+
let inputBasename;
|
|
5199
|
+
const stdinIsPiped = !process.stdin.isTTY;
|
|
5200
|
+
if (opts.input) {
|
|
5201
|
+
const inputPath = (0, import_node_path.resolve)(opts.input);
|
|
5202
|
+
try {
|
|
5203
|
+
content = (0, import_node_fs.readFileSync)(inputPath, "utf-8");
|
|
5204
|
+
} catch {
|
|
5205
|
+
console.error(`Error: Cannot read file "${inputPath}"`);
|
|
5206
|
+
process.exit(1);
|
|
5207
|
+
}
|
|
5208
|
+
const name = (0, import_node_path.basename)(opts.input);
|
|
5209
|
+
const ext = (0, import_node_path.extname)(name);
|
|
5210
|
+
inputBasename = ext ? name.slice(0, -ext.length) : name;
|
|
5211
|
+
} else if (stdinIsPiped) {
|
|
5212
|
+
try {
|
|
5213
|
+
content = (0, import_node_fs.readFileSync)(0, "utf-8");
|
|
5214
|
+
} catch {
|
|
5215
|
+
noInput();
|
|
5216
|
+
}
|
|
5217
|
+
} else {
|
|
5218
|
+
noInput();
|
|
5173
5219
|
}
|
|
5174
5220
|
setupDom();
|
|
5175
5221
|
const isDark = opts.theme === "dark";
|
|
@@ -5181,12 +5227,21 @@ async function main() {
|
|
|
5181
5227
|
);
|
|
5182
5228
|
process.exit(1);
|
|
5183
5229
|
}
|
|
5230
|
+
const format = inferFormat(opts.output);
|
|
5184
5231
|
if (opts.output) {
|
|
5185
5232
|
const outputPath = (0, import_node_path.resolve)(opts.output);
|
|
5186
|
-
|
|
5233
|
+
if (format === "svg") {
|
|
5234
|
+
(0, import_node_fs.writeFileSync)(outputPath, svg, "utf-8");
|
|
5235
|
+
} else {
|
|
5236
|
+
(0, import_node_fs.writeFileSync)(outputPath, svgToPng(svg));
|
|
5237
|
+
}
|
|
5238
|
+
console.error(`Wrote ${outputPath}`);
|
|
5239
|
+
} else if (inputBasename) {
|
|
5240
|
+
const outputPath = (0, import_node_path.resolve)(`${inputBasename}.png`);
|
|
5241
|
+
(0, import_node_fs.writeFileSync)(outputPath, svgToPng(svg));
|
|
5187
5242
|
console.error(`Wrote ${outputPath}`);
|
|
5188
5243
|
} else {
|
|
5189
|
-
process.stdout.write(svg);
|
|
5244
|
+
process.stdout.write(svgToPng(svg));
|
|
5190
5245
|
}
|
|
5191
5246
|
}
|
|
5192
5247
|
main().catch((err) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diagrammo/dgmo",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "DGMO diagram markup language — parser, renderer, and color system",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"dev": "tsup --watch"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
+
"@resvg/resvg-js": "^2.6.2",
|
|
36
37
|
"chart.js": "^4.4.8",
|
|
37
38
|
"chartjs-plugin-datalabels": "^2.2.0",
|
|
38
39
|
"d3-array": "^3.2.4",
|
|
@@ -44,12 +45,12 @@
|
|
|
44
45
|
"jsdom": "^26.0.0"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
|
-
"@types/jsdom": "^21.1.7",
|
|
48
48
|
"@types/d3-array": "^3.2.1",
|
|
49
49
|
"@types/d3-cloud": "^1.2.9",
|
|
50
50
|
"@types/d3-scale": "^4.0.8",
|
|
51
51
|
"@types/d3-selection": "^3.0.11",
|
|
52
52
|
"@types/d3-shape": "^3.1.7",
|
|
53
|
+
"@types/jsdom": "^21.1.7",
|
|
53
54
|
"tsup": "^8.5.1",
|
|
54
55
|
"typescript": "^5.7.3"
|
|
55
56
|
}
|
package/src/cli.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { resolve, basename, extname } from 'node:path';
|
|
3
3
|
import { JSDOM } from 'jsdom';
|
|
4
|
+
import { Resvg } from '@resvg/resvg-js';
|
|
4
5
|
import { renderD3ForExport } from './d3';
|
|
5
6
|
import { getPalette } from './palettes/registry';
|
|
6
7
|
|
|
@@ -18,13 +19,15 @@ const PALETTES = [
|
|
|
18
19
|
const THEMES = ['light', 'dark', 'transparent'] as const;
|
|
19
20
|
|
|
20
21
|
function printHelp(): void {
|
|
21
|
-
console.log(`Usage: dgmo
|
|
22
|
+
console.log(`Usage: dgmo <input> [options]
|
|
23
|
+
cat input.dgmo | dgmo [options]
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
render <input> Render a .dgmo file to SVG
|
|
25
|
+
Render a .dgmo file to PNG (default) or SVG.
|
|
25
26
|
|
|
26
27
|
Options:
|
|
27
|
-
-o <file>
|
|
28
|
+
-o <file> Output file (default: <input>.png in cwd)
|
|
29
|
+
Format inferred from extension: .svg → SVG, else PNG
|
|
30
|
+
With stdin and no -o, PNG is written to stdout
|
|
28
31
|
--theme <theme> Theme: ${THEMES.join(', ')} (default: light)
|
|
29
32
|
--palette <name> Palette: ${PALETTES.join(', ')} (default: nord)
|
|
30
33
|
--help Show this help
|
|
@@ -39,7 +42,6 @@ function printVersion(): void {
|
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
function parseArgs(argv: string[]): {
|
|
42
|
-
command: string | undefined;
|
|
43
45
|
input: string | undefined;
|
|
44
46
|
output: string | undefined;
|
|
45
47
|
theme: (typeof THEMES)[number];
|
|
@@ -48,7 +50,6 @@ function parseArgs(argv: string[]): {
|
|
|
48
50
|
version: boolean;
|
|
49
51
|
} {
|
|
50
52
|
const result = {
|
|
51
|
-
command: undefined as string | undefined,
|
|
52
53
|
input: undefined as string | undefined,
|
|
53
54
|
output: undefined as string | undefined,
|
|
54
55
|
theme: 'light' as (typeof THEMES)[number],
|
|
@@ -92,9 +93,6 @@ function parseArgs(argv: string[]): {
|
|
|
92
93
|
}
|
|
93
94
|
result.palette = val;
|
|
94
95
|
i++;
|
|
95
|
-
} else if (!result.command) {
|
|
96
|
-
result.command = arg;
|
|
97
|
-
i++;
|
|
98
96
|
} else if (!result.input) {
|
|
99
97
|
result.input = arg;
|
|
100
98
|
i++;
|
|
@@ -119,6 +117,55 @@ function setupDom(): void {
|
|
|
119
117
|
Object.defineProperty(globalThis, 'SVGElement', { value: win.SVGElement, configurable: true });
|
|
120
118
|
}
|
|
121
119
|
|
|
120
|
+
function inferFormat(outputPath: string | undefined): 'svg' | 'png' {
|
|
121
|
+
if (outputPath && extname(outputPath).toLowerCase() === '.svg') {
|
|
122
|
+
return 'svg';
|
|
123
|
+
}
|
|
124
|
+
return 'png';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function svgToPng(svg: string): Buffer {
|
|
128
|
+
const resvg = new Resvg(svg, {
|
|
129
|
+
fitTo: { mode: 'zoom', value: 2 },
|
|
130
|
+
});
|
|
131
|
+
const rendered = resvg.render();
|
|
132
|
+
return rendered.asPng();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function noInput(): never {
|
|
136
|
+
const samplePath = resolve('sample.dgmo');
|
|
137
|
+
if (existsSync(samplePath)) {
|
|
138
|
+
console.error('Error: No input file specified');
|
|
139
|
+
console.error(`Try: dgmo ${basename(samplePath)}`);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
writeFileSync(
|
|
143
|
+
samplePath,
|
|
144
|
+
[
|
|
145
|
+
'chart: sequence',
|
|
146
|
+
'activations: off',
|
|
147
|
+
'',
|
|
148
|
+
' Client -> API: POST /login',
|
|
149
|
+
' API -> Auth: validate credentials',
|
|
150
|
+
' Auth -> DB: SELECT user',
|
|
151
|
+
' DB -> Auth: user record',
|
|
152
|
+
' Auth -> API: JWT token',
|
|
153
|
+
' API -> Client: 200 OK { token }',
|
|
154
|
+
'',
|
|
155
|
+
].join('\n'),
|
|
156
|
+
'utf-8'
|
|
157
|
+
);
|
|
158
|
+
console.error(`Created ${samplePath}`);
|
|
159
|
+
console.error('');
|
|
160
|
+
console.error(' Render it: dgmo sample.dgmo');
|
|
161
|
+
console.error(' As SVG: dgmo sample.dgmo -o sample.svg');
|
|
162
|
+
console.error('');
|
|
163
|
+
console.error(
|
|
164
|
+
'Edit sample.dgmo to make it your own, or run dgmo --help for all options.'
|
|
165
|
+
);
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
168
|
+
|
|
122
169
|
async function main(): Promise<void> {
|
|
123
170
|
const opts = parseArgs(process.argv);
|
|
124
171
|
|
|
@@ -132,29 +179,33 @@ async function main(): Promise<void> {
|
|
|
132
179
|
return;
|
|
133
180
|
}
|
|
134
181
|
|
|
135
|
-
|
|
136
|
-
if (opts.command) {
|
|
137
|
-
console.error(`Error: Unknown command "${opts.command}"`);
|
|
138
|
-
} else {
|
|
139
|
-
console.error('Error: No command specified');
|
|
140
|
-
}
|
|
141
|
-
console.error('Run "dgmo --help" for usage');
|
|
142
|
-
process.exit(1);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (!opts.input) {
|
|
146
|
-
console.error('Error: No input file specified');
|
|
147
|
-
console.error('Usage: dgmo render <input> [-o output.svg]');
|
|
148
|
-
process.exit(1);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const inputPath = resolve(opts.input);
|
|
182
|
+
// Determine input source
|
|
152
183
|
let content: string;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
184
|
+
let inputBasename: string | undefined;
|
|
185
|
+
const stdinIsPiped = !process.stdin.isTTY;
|
|
186
|
+
|
|
187
|
+
if (opts.input) {
|
|
188
|
+
// File argument provided
|
|
189
|
+
const inputPath = resolve(opts.input);
|
|
190
|
+
try {
|
|
191
|
+
content = readFileSync(inputPath, 'utf-8');
|
|
192
|
+
} catch {
|
|
193
|
+
console.error(`Error: Cannot read file "${inputPath}"`);
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
// Strip extension for default output name
|
|
197
|
+
const name = basename(opts.input);
|
|
198
|
+
const ext = extname(name);
|
|
199
|
+
inputBasename = ext ? name.slice(0, -ext.length) : name;
|
|
200
|
+
} else if (stdinIsPiped) {
|
|
201
|
+
// Read from stdin
|
|
202
|
+
try {
|
|
203
|
+
content = readFileSync(0, 'utf-8');
|
|
204
|
+
} catch {
|
|
205
|
+
noInput();
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
noInput();
|
|
158
209
|
}
|
|
159
210
|
|
|
160
211
|
// Set up jsdom before any d3/renderer code runs
|
|
@@ -174,12 +225,26 @@ async function main(): Promise<void> {
|
|
|
174
225
|
process.exit(1);
|
|
175
226
|
}
|
|
176
227
|
|
|
228
|
+
// Determine output format and destination
|
|
229
|
+
const format = inferFormat(opts.output);
|
|
230
|
+
|
|
177
231
|
if (opts.output) {
|
|
232
|
+
// Explicit output path
|
|
178
233
|
const outputPath = resolve(opts.output);
|
|
179
|
-
|
|
234
|
+
if (format === 'svg') {
|
|
235
|
+
writeFileSync(outputPath, svg, 'utf-8');
|
|
236
|
+
} else {
|
|
237
|
+
writeFileSync(outputPath, svgToPng(svg));
|
|
238
|
+
}
|
|
239
|
+
console.error(`Wrote ${outputPath}`);
|
|
240
|
+
} else if (inputBasename) {
|
|
241
|
+
// File input, no -o → write <basename>.png in cwd
|
|
242
|
+
const outputPath = resolve(`${inputBasename}.png`);
|
|
243
|
+
writeFileSync(outputPath, svgToPng(svg));
|
|
180
244
|
console.error(`Wrote ${outputPath}`);
|
|
181
245
|
} else {
|
|
182
|
-
|
|
246
|
+
// Stdin input, no -o → write PNG to stdout
|
|
247
|
+
process.stdout.write(svgToPng(svg));
|
|
183
248
|
}
|
|
184
249
|
}
|
|
185
250
|
|