From 71aaec03bf9af01ccb132e09882f35532649da23 Mon Sep 17 00:00:00 2001 From: waaraawa Date: Mon, 13 Oct 2025 09:34:29 +0900 Subject: [PATCH] chore: initial project setup --- .eslintrc.json | 33 ++++++++++ .gitignore | 40 ++++++++++++ .prettierignore | 5 ++ .prettierrc.json | 10 +++ README.md | 77 ++++++++++++++++++++++ jest.config.js | 22 +++++++ package.json | 42 ++++++++++++ packages/core/jest.config.js | 7 ++ packages/core/package.json | 26 ++++++++ packages/core/src/errors.ts | 58 +++++++++++++++++ packages/core/src/index.ts | 12 ++++ packages/core/src/types.ts | 123 +++++++++++++++++++++++++++++++++++ packages/core/tsconfig.json | 9 +++ tsconfig.json | 24 +++++++ 14 files changed, 488 insertions(+) create mode 100644 .eslintrc.json create mode 100644 .gitignore create mode 100644 .prettierignore create mode 100644 .prettierrc.json create mode 100644 README.md create mode 100644 jest.config.js create mode 100644 package.json create mode 100644 packages/core/jest.config.js create mode 100644 packages/core/package.json create mode 100644 packages/core/src/errors.ts create mode 100644 packages/core/src/index.ts create mode 100644 packages/core/src/types.ts create mode 100644 packages/core/tsconfig.json create mode 100644 tsconfig.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..e8a2566 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module", + "project": "./tsconfig.json" + }, + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking" + ], + "rules": { + "@typescript-eslint/no-unused-vars": [ + "error", + { "argsIgnorePattern": "^_" } + ], + "@typescript-eslint/explicit-function-return-type": [ + "warn", + { "allowExpressions": true } + ], + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-non-null-assertion": "warn", + "no-console": ["warn", { "allow": ["warn", "error"] }] + }, + "env": { + "node": true, + "es6": true + }, + "ignorePatterns": ["dist", "node_modules", "*.js"] +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e71adf --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Dependencies +node_modules/ +package-lock.json +yarn.lock + +# Build outputs +dist/ +*.tsbuildinfo + +# Test coverage +coverage/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Environment +.env +.env.local +.env.*.local + +# Temporary files +*.tmp +.cache/ + +# Backup files +*.backup diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..7717b0c --- /dev/null +++ b/.prettierignore @@ -0,0 +1,5 @@ +node_modules +dist +coverage +*.log +.git diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..32a2397 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,10 @@ +{ + "semi": true, + "trailingComma": "es5", + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2, + "useTabs": false, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..c9a7e90 --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +# ByteGrid + +> Binary data and C struct memory layout visualization for Obsidian + +## Overview + +**ByteGrid** is an Obsidian plugin that visualizes binary data and C structure memory layouts as interactive SVG diagrams. + +## Features + +- 🎨 Color-coded field visualization +- 📏 Byte-accurate grid layout +- 🔍 Bitfield support +- 📊 Hex dump integration +- 🎯 Interactive tooltips +- 📤 Multiple export formats (SVG, PNG, C code, Markdown) + +## Project Status + +🚧 **In Development** - Currently in Phase 1 (MVP) + +## Quick Start + +```bash +# Install dependencies +npm install + +# Build all packages +npm run build + +# Run tests +npm run test + +# Lint +npm run lint + +# Format code +npm run format +``` + +## Project Structure + +``` +bytegrid/ +├── packages/ +│ ├── core/ # Core rendering logic +│ └── obsidian-plugin/ # Obsidian plugin +├── docs/ # Design documentation +└── examples/ # Example files +``` + +## Documentation + +See [CLAUDE.md](./CLAUDE.md) for detailed project guidelines and architecture. + +## Development + +This project follows **Test-Driven Development (TDD)**: + +1. Write tests first +2. Implement minimal code to pass tests +3. Refactor + +### Key Principles + +- **offset is SSOT** - Field size calculated from offset ranges +- **No magic numbers** - Use constants for all layout values +- **Dynamic height** - SVG dimensions calculated from content +- **Explicit padding** - Use `reserved` or `padding` types + +## License + +MIT License - see [LICENSE](./LICENSE) for details + +## Contributing + +Currently in initial development phase. Contribution guidelines will be added soon. diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..428264c --- /dev/null +++ b/jest.config.js @@ -0,0 +1,22 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + roots: ['/packages'], + testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'], + collectCoverageFrom: [ + 'packages/*/src/**/*.ts', + '!packages/*/src/**/*.d.ts', + '!packages/*/src/index.ts', + ], + coverageThreshold: { + global: { + branches: 80, + functions: 80, + lines: 80, + statements: 80, + }, + }, + moduleNameMapper: { + '^@bytegrid/core$': '/packages/core/src', + }, +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..f0475f7 --- /dev/null +++ b/package.json @@ -0,0 +1,42 @@ +{ + "name": "bytegrid", + "version": "0.1.0", + "description": "Binary data and C struct memory layout visualization for Obsidian", + "private": true, + "workspaces": [ + "packages/*" + ], + "scripts": { + "build": "npm run build --workspaces", + "test": "npm run test --workspaces", + "lint": "eslint . --ext .ts", + "format": "prettier --write \"**/*.{ts,json,md}\"", + "format:check": "prettier --check \"**/*.{ts,json,md}\"", + "clean": "rm -rf packages/*/dist packages/*/node_modules node_modules" + }, + "keywords": [ + "obsidian", + "obsidian-plugin", + "binary", + "visualization", + "memory-layout", + "struct" + ], + "author": "ByteGrid Contributors", + "license": "MIT", + "devDependencies": { + "@types/jest": "^29.5.11", + "@types/node": "^20.10.6", + "@typescript-eslint/eslint-plugin": "^6.17.0", + "@typescript-eslint/parser": "^6.17.0", + "eslint": "^8.56.0", + "jest": "^29.7.0", + "prettier": "^3.1.1", + "ts-jest": "^29.1.1", + "typescript": "^5.3.3" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=9.0.0" + } +} diff --git a/packages/core/jest.config.js b/packages/core/jest.config.js new file mode 100644 index 0000000..e5330c3 --- /dev/null +++ b/packages/core/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + roots: ['/tests'], + testMatch: ['**/?(*.)+(spec|test).ts'], + collectCoverageFrom: ['src/**/*.ts', '!src/**/*.d.ts', '!src/index.ts'], +}; diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 0000000..c22cc38 --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,26 @@ +{ + "name": "@bytegrid/core", + "version": "0.1.0", + "description": "Core rendering logic for ByteGrid", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "test": "jest", + "test:watch": "jest --watch", + "test:coverage": "jest --coverage" + }, + "keywords": [ + "bytegrid", + "binary", + "visualization" + ], + "author": "ByteGrid Contributors", + "license": "MIT", + "dependencies": { + "js-yaml": "^4.1.0" + }, + "devDependencies": { + "@types/js-yaml": "^4.0.9" + } +} diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts new file mode 100644 index 0000000..04b1ac5 --- /dev/null +++ b/packages/core/src/errors.ts @@ -0,0 +1,58 @@ +/** + * Custom error classes for ByteGrid + */ + +/** + * Base error class for ByteGrid + */ +export class ByteGridError extends Error { + constructor(message: string) { + super(message); + this.name = 'ByteGridError'; + Object.setPrototypeOf(this, ByteGridError.prototype); + } +} + +/** + * Error thrown during YAML parsing + */ +export class ParseError extends ByteGridError { + constructor(message: string, public readonly fieldIndex?: number) { + super(message); + this.name = 'ParseError'; + Object.setPrototypeOf(this, ParseError.prototype); + } +} + +/** + * Error thrown during validation + */ +export class ValidationError extends ByteGridError { + constructor(message: string, public readonly fieldIndex?: number) { + super(message); + this.name = 'ValidationError'; + Object.setPrototypeOf(this, ValidationError.prototype); + } +} + +/** + * Error thrown during rendering + */ +export class RenderError extends ByteGridError { + constructor(message: string) { + super(message); + this.name = 'RenderError'; + Object.setPrototypeOf(this, RenderError.prototype); + } +} + +/** + * Error thrown during binary parsing + */ +export class BinaryParseError extends ByteGridError { + constructor(message: string, public readonly offset?: number) { + super(message); + this.name = 'BinaryParseError'; + Object.setPrototypeOf(this, BinaryParseError.prototype); + } +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts new file mode 100644 index 0000000..6672a89 --- /dev/null +++ b/packages/core/src/index.ts @@ -0,0 +1,12 @@ +/** + * ByteGrid Core - Public API + */ + +export * from './types'; +export * from './errors'; + +// TODO: Export parser, validator, layoutEngine, svgRenderer when implemented +// export { parse } from './parser'; +// export { validate } from './validator'; +// export { createLayout } from './layoutEngine'; +// export { renderSVG } from './svgRenderer'; diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts new file mode 100644 index 0000000..9935393 --- /dev/null +++ b/packages/core/src/types.ts @@ -0,0 +1,123 @@ +/** + * Core type definitions for ByteGrid + */ + +/** + * Supported data types in ByteGrid + */ +export type DataType = + | 'char' + | 'int8_t' + | 'uint8_t' + | 'int16_t' + | 'uint16_t' + | 'short' + | 'int32_t' + | 'uint32_t' + | 'int' + | 'int64_t' + | 'uint64_t' + | 'long' + | 'float' + | 'double' + | 'reserved' + | 'padding' + | string; // For array types like 'char[4]' + +/** + * Endianness for multi-byte fields + */ +export type Endianness = 'little' | 'big'; + +/** + * Color names for field visualization + */ +export type ColorName = + | 'blue' + | 'cyan' + | 'yellow' + | 'green' + | 'orange' + | 'purple' + | 'mint' + | 'pink' + | 'gray'; + +/** + * Color scheme variants + */ +export type ColorScheme = 'default' | 'dark' | 'light'; + +/** + * Bitfield definition within a field + */ +export interface Bitfield { + name: string; + bits: string; // e.g., "0-3" or "7" + description?: string; +} + +/** + * Field definition + * Note: size is calculated from offset (SSOT principle) + */ +export interface Field { + offset: string; // e.g., "0-3" or "4" (SSOT for size calculation) + name: string; + type: DataType; + value?: string; + description?: string; + color?: ColorName; + endianness?: Endianness; + bitfields?: Bitfield[]; +} + +/** + * Main configuration for ByteGrid visualization + */ +export interface ByteGridConfig { + name: string; + size: number; // Total size in bytes + layout?: number; // Bytes per row (default: 16) + colorScheme?: ColorScheme; + fields: Field[]; +} + +/** + * Parsed offset information + */ +export interface OffsetRange { + start: number; + end: number; + size: number; +} + +/** + * Layout block for rendering (after layout engine processing) + */ +export interface LayoutBlock { + row: number; + col: number; + span: number; // Number of columns this block spans + fieldName: string; + fieldType: DataType; + color: ColorName; + value?: string; + description?: string; + offsetStart: number; + offsetEnd: number; + isPadding: boolean; + bitfields?: Bitfield[]; +} + +/** + * Rendering options + */ +export interface RenderOptions { + showHexDump?: boolean; + showLegend?: boolean; + showGrid?: boolean; + cellWidth?: number; + cellHeight?: number; + fontSize?: number; +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 0000000..2a28f2b --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "tests"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..b5673d2 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./", + "composite": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "moduleResolution": "node", + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "exclude": ["node_modules", "dist", "**/*.test.ts"] +}