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
11 changes: 6 additions & 5 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ jobs:
- name: Install dependencies
run: bun install --frozen-lockfile

- name: Run tests
run: bun test

- name: Run tests with coverage
run: bun test --coverage
run: bun test --coverage --coverage-reporter=lcov

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
files: ./coverage/lcov.info
flags: unittests
name: codecov-umbrella
fail_ci_if_error: true
verbose: true

- name: Run linting (OxLint)
run: bun run lint
Expand Down
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ LogsDX is a schema-based theming engine that applies consistent visual styling t

## Features

- 🎨 **Unified Theming** - One theme works in terminal, browser, and CI/CD
- 🚀 **Zero Dependencies** - Works with any existing logger
- 📦 **8+ Built-in Themes** - Production-ready themes included
- 🛠️ **CLI Tool** - Process log files with beautiful formatting
- **Accessible** - WCAG compliance checking built-in
- 🌓 **Light/Dark Mode** - Automatic theme adaptation
- **Unified Theming** - One theme works in terminal, browser, and CI/CD
- **Zero Dependencies** - Works with any existing logger
- **8+ Built-in Themes** - Production-ready themes included
- **CLI Tool** - Process log files with beautiful formatting
- **Accessible** - WCAG compliance checking built-in
- **Light/Dark Mode** - Automatic theme adaptation

## Installation

Expand Down Expand Up @@ -514,17 +514,17 @@ bun run format # Format code

The setup script will:

- Install all dependencies
- Build the main package
- Configure git hooks (pre-commit, post-merge, post-checkout)
- Verify your environment is ready
- Install all dependencies
- Build the main package
- Configure git hooks (pre-commit, post-merge, post-checkout)
- Verify your environment is ready

## License

MIT © LogsDX Contributors

## Support

- 📘 [Documentation](https://jeffry.in/logsdx)
- 🐛 [Report Issues](https://github.com/yowainwright/logsdx/issues)
- 💬 [Discussions](https://github.com/yowainwright/logsdx/discussions)
- [Documentation](https://jeffry.in/logsdx)
- [Report Issues](https://github.com/yowainwright/logsdx/issues)
- [Discussions](https://github.com/yowainwright/logsdx/discussions)
36 changes: 36 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
codecov:
require_ci_to_pass: yes

coverage:
precision: 2
round: down
range: "85...100"

status:
project:
default:
target: 95%
threshold: 1%
if_ci_failed: error

patch:
default:
target: 90%
threshold: 5%

comment:
layout: "reach, diff, flags, files"
behavior: default
require_changes: false
require_base: false
require_head: true

ignore:
- "tests/**/*"
- "**/*.test.ts"
- "**/*.config.ts"
- "**/*.config.js"
- "scripts/**/*"
- "site/**/*"
- "examples/**/*"
- "dist/**/*"
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"build:cli": "bun build src/cli/bin.ts --outfile dist/cli.js --format cjs --minify --target node",
"build:types": "tsc -p tsconfig.build.json",
"test": "bun test",
"test:coverage": "bun test --coverage --coverage-reporter=lcov",
"test:watch": "bun test --watch",
"lint": "oxlint .",
"lint:fix": "oxlint . --fix",
Expand Down
6 changes: 3 additions & 3 deletions scripts/install-hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ import { join } from "path";
const HOOKS_DIR = ".git/hooks";

const PRE_COMMIT = `#!/bin/sh
cd "\$(git rev-parse --show-toplevel)" || exit 1
cd "$(git rev-parse --show-toplevel)" || exit 1
bun run format && bun run lint && bun test
`;

const POST_CHECKOUT = `#!/bin/sh
changed=\$(git diff-tree -r --name-only --no-commit-id $1 $2 2>/dev/null)
changed=$(git diff-tree -r --name-only --no-commit-id $1 $2 2>/dev/null)
if echo "$changed" | grep -q "package.json\\|bun.lock"; then
echo "Dependencies changed, running bun install..."
bun install
fi
`;

const POST_MERGE = `#!/bin/sh
changed=\$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD 2>/dev/null)
changed=$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD 2>/dev/null)
if echo "$changed" | grep -q "package.json\\|bun.lock"; then
echo "Dependencies changed, running bun install..."
bun install
Expand Down
97 changes: 97 additions & 0 deletions scripts/remove-comments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env bun

import { readdir, readFile, writeFile } from "fs/promises";
import { join } from "path";

async function getAllTsFiles(dir: string): Promise<string[]> {
const files: string[] = [];
const entries = await readdir(dir, { withFileTypes: true });

for (const entry of entries) {
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
files.push(...(await getAllTsFiles(fullPath)));
} else if (entry.name.endsWith(".ts")) {
files.push(fullPath);
}
}

return files;
}

function removeComments(code: string): string {
let result = "";
let i = 0;
let inString = false;
let stringChar = "";
let inTemplate = false;

while (i < code.length) {
const char = code[i];
const nextChar = code[i + 1];

if (!inString && !inTemplate && char === "/" && nextChar === "/") {
const lineEnd = code.indexOf("\n", i);
if (lineEnd === -1) {
break;
}
result += "\n";
i = lineEnd + 1;
continue;
}

if (!inString && !inTemplate && char === "/" && nextChar === "*") {
const commentEnd = code.indexOf("*/", i + 2);
if (commentEnd === -1) {
break;
}
const commentContent = code.substring(i, commentEnd + 2);
const newlines = (commentContent.match(/\n/g) || []).length;
result += "\n".repeat(newlines);
i = commentEnd + 2;
continue;
}

if (!inTemplate && (char === '"' || char === "'")) {
if (!inString) {
inString = true;
stringChar = char;
} else if (char === stringChar && code[i - 1] !== "\\") {
inString = false;
stringChar = "";
}
}

if (!inString && char === "`") {
inTemplate = !inTemplate;
}

result += char;
i++;
}

return result;
}

async function processFile(filePath: string) {
console.log(`Processing: ${filePath}`);
const content = await readFile(filePath, "utf-8");
const cleaned = removeComments(content);
await writeFile(filePath, cleaned, "utf-8");
}

async function main() {
const srcFiles = await getAllTsFiles("src");
const testFiles = await getAllTsFiles("tests");
const allFiles = [...srcFiles, ...testFiles];

console.log(`Found ${allFiles.length} TypeScript files`);

for (const file of allFiles) {
await processFile(file);
}

console.log("Done!");
}

main().catch(console.error);
2 changes: 1 addition & 1 deletion src/cli/bin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env node
import { createCLI } from "../utils/cli";
import { createCLI } from "./parser";
import { main } from "./index";
import type { CommanderOptions } from "./types";
import { version } from "../../package.json";
Expand Down
29 changes: 10 additions & 19 deletions src/cli/commands/theme.ts → src/cli/commands.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import { createCLI, CLI } from "../../utils/cli";
import { input, select, checkbox, confirm } from "../../utils/prompts";
import spinner from "../../utils/spinner";
import * as colorUtil from "../../utils/colors";
import gradient from "../../utils/gradient";
import boxen from "../../utils/boxen";
import { createCLI, CLI } from "./parser";
import { input, select, checkbox, confirm } from "../utils/prompts";
import spinner from "../utils/spinner";
import * as colorUtil from "../utils/colors";
import gradient from "../utils/gradient";
import boxen from "../utils/boxen";
import { writeFileSync, existsSync, mkdirSync } from "fs";
import { dirname } from "path";
import {
createTheme,
checkWCAGCompliance,
adjustThemeForAccessibility,
SimpleThemeConfig,
} from "../../themes/builder";
import { registerTheme, getTheme, getThemeNames } from "../../themes";
import { getLogsDX } from "../../index";
import { Theme } from "../../types";
} from "../themes/builder";
import { registerTheme, getTheme, getThemeNames } from "../themes";
import { getLogsDX } from "../index";
import { Theme } from "../types";

// Sample logs for preview
const SAMPLE_LOGS = [
"INFO: Server started on port 3000",
"WARN: Memory usage high: 85%",
Expand All @@ -28,7 +27,6 @@ const SAMPLE_LOGS = [
"Cache hit ratio: 92.5%",
];

// Color presets
const COLOR_PRESETS = {
Vibrant: {
primary: "#007acc",
Expand Down Expand Up @@ -105,7 +103,6 @@ async function createInteractiveTheme(options: { skipIntro?: boolean } = {}) {
showBanner();
}

// Basic info
const name = await input({
message: "Theme name:",
validate: (inputValue: string) => {
Expand Down Expand Up @@ -138,7 +135,6 @@ async function createInteractiveTheme(options: { skipIntro?: boolean } = {}) {
mode,
};

// Color selection
const preset = await select({
message: "Choose a color preset:",
choices: Object.keys(COLOR_PRESETS).map((name) => ({
Expand Down Expand Up @@ -211,7 +207,6 @@ async function createInteractiveTheme(options: { skipIntro?: boolean } = {}) {
colors = { primary, error, warning, success, info, muted };
}

// Feature presets
const presets = await checkbox({
message: "Select features to highlight:",
choices: [
Expand All @@ -236,7 +231,6 @@ async function createInteractiveTheme(options: { skipIntro?: boolean } = {}) {
],
});

// Create theme
const createSpinner = spinner("Creating theme...").start();

const config: SimpleThemeConfig = {
Expand All @@ -250,11 +244,9 @@ async function createInteractiveTheme(options: { skipIntro?: boolean } = {}) {
const theme = createTheme(config);
createSpinner.succeed("Theme created!");

// Preview
console.log("\n");
renderPreview(theme, `✨ ${theme.name} Preview`);

// Accessibility check
const checkAccessibility = await confirm({
message: "Check accessibility compliance?",
default: true,
Expand Down Expand Up @@ -301,7 +293,6 @@ async function createInteractiveTheme(options: { skipIntro?: boolean } = {}) {
}
}

// Save options
const saveOption = await select({
message: "How would you like to save the theme?",
choices: [
Expand Down
5 changes: 2 additions & 3 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { createCLI } from "../utils/cli";
import fs from "fs";
import path from "path";
import { LogsDX, getThemeNames } from "../index";
Expand All @@ -15,8 +14,8 @@ import {
runThemeGenerator,
listColorPalettesCommand,
listPatternPresetsCommand,
} from "./theme/generator";
import { exportTheme, importTheme, listThemeFiles } from "./theme/transporter";
} from "./theme-gen";
import { exportTheme, importTheme, listThemeFiles } from "./theme-gen";

export function loadConfig(configPath?: string): LogsDXOptions {
const defaultConfig: LogsDXOptions = {
Expand Down
3 changes: 0 additions & 3 deletions src/cli/interactive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ export async function runInteractiveMode(): Promise<InteractiveConfig> {
),
);

// Theme selection
const themeNames = getThemeNames();
const themeChoices: ThemeChoice[] = themeNames.map((name: string) => ({
name: chalk.cyan(name),
Expand Down Expand Up @@ -79,7 +78,6 @@ export async function runInteractiveMode(): Promise<InteractiveConfig> {
});
}

// Output format selection
const outputFormat = await select({
message: "📤 Choose output format:",
choices: [
Expand All @@ -96,7 +94,6 @@ export async function runInteractiveMode(): Promise<InteractiveConfig> {
],
});

// Preview confirmation
const wantPreview = await confirm({
message: "👀 Show a preview with your settings?",
default: true,
Expand Down
Loading