Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
node_modules/

dist
dist
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,15 @@ Run the build script to generate `.json` files from all `.jsonnet` files in the
npm run buildJson
```

### 3. Validate output completeness
### 3. Build Mermaid diagrams

Run the build script to generate `.mmd` diagrams from all `.json` files in the `generated/json` directory:

```bash
npm run buildDiagrams
```

### 4. Validate output completeness

Check that all `.jsonnet` files have corresponding `.json` outputs:

Expand All @@ -77,8 +85,9 @@ To define a new logging feature:

1. Create a `.jsonnet` file under `features/<your-feature>/`
2. Run `npm run buildJson` to generate the `.json` file
3. Add a test under `__tests__/<your-feature>.test.js`
4. Run `npm test` to validate
3. Run `npm run buildDiagrams` to generate the `.mmd` file
4. Add a test under `__tests__/<your-feature>.test.js`
5. Run `npm test` to validate

---

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"scripts": {
"build": "tsc",
"buildJson": "npx tsx scripts/generate-json-definitions.ts",
"buildDiagrams": "npx tsx scripts/generate-diagrams.ts",
"validateGeneration": "npx tsx scripts/validate-json-generated.ts",
"test": "jest"
},
Expand Down
75 changes: 75 additions & 0 deletions scripts/generate-diagrams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { walkDir, isJsonFile, getMermaidOutputPath } from "./utils";
import logger from "./log-styling";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const INPUT_DIR = path.resolve(__dirname, "../generated/json");
const OUTPUT_DIR = path.resolve(__dirname, "../generated/mermaid");

type Event = {
id: string;
label: string;
next?: string;
success?: string;
error?: string;
};

function toMermaid(events: Event[]): string {
const lines: string[] = ["graph TD"];

for (const event of events) {
const { id, label, next, success, error } = event;

lines.push(`${id}["${label}"]`);
if (next) {
lines.push(`${id} --> ${next}`);
}
if (success) {
lines.push(`${id} -->|Success| ${success}`);
}
if (error) {
lines.push(`${id} -->|Error| ${error}`);
}
}

return lines.join("\n");
}

function generateDiagram(filePath: string): void {
const relativePath = path.relative(INPUT_DIR, filePath);
logger.info(`Generating diagram for: ${relativePath}`);

const outputFile = getMermaidOutputPath(filePath, INPUT_DIR, OUTPUT_DIR);
fs.mkdirSync(path.dirname(outputFile), { recursive: true });

const events: Event[] = JSON.parse(fs.readFileSync(filePath, "utf-8"));
const output = toMermaid(events);

fs.writeFileSync(outputFile, output);
}

if (!fs.existsSync(INPUT_DIR)) {
logger.warn(`Generated directory is missing: ${INPUT_DIR}`);
logger.info("This likely means you need to run 'npm run buildJson'");
process.exit(0);
}

logger.heading("Generating Mermaid diagrams from JSON files...");
logger.blank();

walkDir(INPUT_DIR, (filePath: string) => {
if (isJsonFile(filePath)) {
generateDiagram(filePath);
} else {
logger.warn(
`Skipping unsupported file: ${path.relative(INPUT_DIR, filePath)}`
);
}
});

logger.blank();
logger.success("Mermaid diagrams generated successfully!");
4 changes: 2 additions & 2 deletions scripts/generate-json-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
walkDir,
isJsonnetFile,
isLibSonnetFile,
getOutputPath,
getJsonOutputPath,
} from "./utils";
import logger from "./log-styling";

Expand All @@ -18,7 +18,7 @@ const OUTPUT_DIR = path.resolve(__dirname, "../generated/json");

function buildJsonnetFile(inputPath: string): void {
const relativePath = path.relative(INPUT_DIR, inputPath);
const outputFile = getOutputPath(inputPath, INPUT_DIR, OUTPUT_DIR);
const outputFile = getJsonOutputPath(inputPath, INPUT_DIR, OUTPUT_DIR);

fs.mkdirSync(path.dirname(outputFile), { recursive: true });

Expand Down
21 changes: 20 additions & 1 deletion scripts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,33 @@ export function isLibSonnetFile(file: string) {
return file.endsWith(".libsonnet");
}

/**
* Determines if a file is a valid JSON file
*/
export function isJsonFile(file: string) {
return file.endsWith(".json");
}

/**
* Converts a .jsonnet input path to a .json output path.
*/
export function getOutputPath(
export function getJsonOutputPath(
inputPath: string,
inputRoot: string,
outputRoot: string
) {
const relativePath = path.relative(inputRoot, inputPath);
return path.join(outputRoot, relativePath.replace(/\.jsonnet$/, ".json"));
}

/**
* Converts a .json input path to a .mmd output path.
*/
export function getMermaidOutputPath(
inputPath: string,
inputRoot: string,
outputRoot: string
) {
const relativePath = path.relative(inputRoot, inputPath);
return path.join(outputRoot, relativePath.replace(/\.json$/, ".mmd"));
}
4 changes: 2 additions & 2 deletions scripts/validate-json-generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import logger from "./log-styling";
import { walkDir, isJsonnetFile, getOutputPath } from "./utils";
import { walkDir, isJsonnetFile, getJsonOutputPath } from "./utils";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
Expand All @@ -20,7 +20,7 @@ const missingFiles: string[] = [];
walkDir(INPUT_DIR, (inputPath: string) => {
if (isJsonnetFile(inputPath)) {
const relativePath = path.relative(INPUT_DIR, inputPath);
const expectedOutputPath = getOutputPath(inputPath, INPUT_DIR, OUTPUT_DIR);
const expectedOutputPath = getJsonOutputPath(inputPath, INPUT_DIR, OUTPUT_DIR);

if (!fs.existsSync(expectedOutputPath)) {
missingFiles.push(relativePath);
Expand Down