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
101 changes: 86 additions & 15 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,33 @@

## Project Overview

A Zig library (`version_info` module) with CLI executable, demonstrating Zig's dual library+executable pattern. Minimal NPM integration for metadata only - this is NOT a Node.js project.
A Zig library (`version_info` module) with CLI executable that generates TypeScript version information files from package.json. Demonstrates Zig's dual library+executable pattern with minimal NPM integration for metadata only - this is NOT a Node.js project.

### Core Functionality

- Reads version from `package.json`
- Generates ISO 8601 timestamps
- Extracts git information (branch and commit hash) from `.git` folder
- Outputs TypeScript file with `VERSION_INFO` constant
- Handles non-git repositories gracefully (optional git info)

## Architecture

### Dual-Module Structure

- **Library module** ([src/root.zig](../src/root.zig)): Public API via `version_info` module
- Entry point for consumers using `@import("version_info")`
- Public functions: `printVersion()`, `generateVersionInfo()`, `getGitInfo()`
- Only public declarations in root.zig are accessible to external code
- **Executable** ([src/main.zig](../src/main.zig)): CLI wrapper that imports and uses the library
- Parses command-line arguments (`--version`, `--input`, `--output`)
- Delegates to library functions
- Separate business logic from CLI concerns
- Root module imports library module as dependency

This separation allows consumers to either:

1. Use as a library by importing the `version_info` module
2. Use as a standalone CLI tool
2. Use as a standalone CLI tool via `zig-out/bin/version_info`

## Development Workflows

Expand All @@ -28,11 +38,12 @@ This separation allows consumers to either:
# Build executable (output: zig-out/bin/version_info)
zig build

# Run executable directly
# Run executable directly (generates version-info.ts)
zig build run

# Run with arguments
zig build run -- arg1 arg2
zig build run -- --input package.json --output version-info.ts
zig build run -- --version

# Run all tests (runs both library and executable tests in parallel)
zig build test
Expand All @@ -49,33 +60,81 @@ rm -rf zig-cache zig-out
- `b.addModule()` exposes modules to package consumers
- `b.createModule()` creates internal modules (not exposed)

## Core Implementation Details

### Git Information Reading

- Reads `.git/HEAD` to determine current branch reference
- Parses `refs/heads/branch-name` format
- Reads commit hash from `.git/refs/heads/{branch}` file
- Handles detached HEAD state
- Returns `null` if not in a git repository (graceful degradation)

### TypeScript Output Format

```typescript
export const VERSION_INFO = {
version: "0.0.3",
date: "2025-12-26T16:00:00.000Z",
git: {
branch: "master",
commit: "324822ac3893dd6159ab8cb4477d45edeacf11f6",
},
};
```

Git section is **optional** - omitted when not in a git repository.

### Memory Management Patterns

- `getGitInfo()` allocates memory for branch and commit strings
- Caller must free using `allocator.free()` for both fields
- Use explicit cleanup after file writing to avoid use-after-free
- Example pattern:
```zig
const git_info = try getGitInfo(allocator);
// ... use git_info ...
if (git_info) |info| {
allocator.free(info.branch);
allocator.free(info.commit);
}
```

## Testing

### Test Organization

- Library tests: in [src/root.zig](../src/root.zig) (e.g., `test "basic add functionality"`)
- Executable tests: in [src/main.zig](../src/main.zig) (e.g., `test "simple test"`, `test "fuzz example"`)
- Library tests: in [src/root.zig](../src/root.zig)
- Executable tests: in [src/main.zig](../src/main.zig)
- Both test suites run in parallel via `zig build test`

### Fuzzing Support
### Testing Git Functionality

Use `--fuzz` flag for fuzz testing: `zig build test --fuzz`
Example in [src/main.zig](../src/main.zig#L20-L27) shows `std.testing.fuzz()` pattern
- Requires actual `.git` folder for integration testing
- Test null case by running in non-git directory
- Memory leak tests automatically verify proper cleanup

## Conventions

### Memory Management

- Explicit allocator passing (see `std.testing.allocator` usage)
- **Critical**: Always `defer` cleanup (e.g., `defer list.deinit(gpa)`)
- **Critical**: Always `defer` cleanup or explicit free at appropriate scope
- Avoid `defer` in optional capture blocks - use explicit cleanup after usage
- Zig detects memory leaks in tests automatically

### Output Handling

- `std.debug.print()` → stderr (debugging)
- `std.debug.print()` → stderr (debugging/logging with colored output)
- `std.fs.File.stdout()` → stdout (actual program output)
- Buffered writers require explicit `.flush()` calls

### Colored Console Output

- Uses ANSI escape codes defined in `Color` struct
- Helper `log()` function for consistent emoji + color formatting
- Example: `log(Color.BRIGHT_GREEN, "✅", "Successfully generated {s}", .{path});`

### Module Imports

```zig
Expand All @@ -102,12 +161,14 @@ const version_info = @import("version_info"); // Local module

### NPM Integration

[package.json](../package.json) contains metadata only (author, license). No Node.js runtime usage.
[package.json](../package.json) contains metadata only (author, license, scripts). No Node.js runtime usage.

Scripts are for building/publishing the Zig executable as an NPM package.

### Publishing

- `.paths` in build.zig.zon defines published files (build.zig, build.zig.zon, src/)
- Consider adding LICENSE/README.md to .paths before publishing
- `.paths` in build.zig.zon defines published files (build.zig, build.zig.zon, src/, LICENSE, README.md)
- Binary published via NPM with bin entry pointing to `zig-out/bin/version_info`

## Common Patterns

Expand All @@ -116,6 +177,14 @@ const version_info = @import("version_info"); // Local module
1. Add to [src/root.zig](../src/root.zig) with `pub` keyword
2. Write corresponding `test` block
3. Re-export from root.zig if defined in other files
4. Ensure proper memory management for allocated resources

### Error Handling

- Use `try` for propagating errors
- Catch specific errors with `catch |err|` for graceful degradation
- Return optional types (`?T`) for operations that may fail non-critically
- Example: `getGitInfo()` returns `?GitInfo` and handles `FileNotFound` gracefully

### Creating New Dependencies

Expand All @@ -126,3 +195,5 @@ Edit [build.zig](../build.zig) `.imports` array in `exe.root_module` or module d
- Zig build is declarative: mutations to build graph (`b`), not direct compilation
- Test executables test ONE module at a time (requires separate test instances)
- Always specify target when creating modules used in tests
- Optional captures create new variable scope - avoid `defer` within them
- File operations must handle both git and non-git environments gracefully
170 changes: 165 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,173 @@
## Version Info
# Package Version Info

[![npm version](https://badge.fury.io/js/package-version-info.svg)](https://badge.fury.io/js/package-version-info)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A blazingly fast CLI tool written in Zig that generates TypeScript version information files from your `package.json`. Perfect for embedding version, build date, and git information into your applications.

## ✨ Features

- 🚀 **Fast**: Written in Zig for maximum performance
- 📦 **Zero Dependencies**: No runtime dependencies required
- 👤 **Author Information**: Extracts author details from package.json
- 🌿 **Git Integration**: Automatically extracts branch and commit information
- ⚡ **TypeScript Output**: Generates type-safe TypeScript constants
- 🎯 **Graceful Degradation**: Works with or without a git repository or author info
- 🔧 **Configurable**: Customize input and output paths

## 🚀 Quick Start

### Installation

```bash
npm install package-version-info --save-dev
# or
yarn add package-version-info --dev
```

### Usage

```bash
# Generate version-info.ts from package.json
npx package-version-info

# Show version
npx package-version-info --version

# Custom paths
npx package-version-info --input package.json --output src/version-info.ts
```

### Output Example

**Full Output (with author and git):**

```typescript
export const VERSION_INFO = {
version: "1.0.0",
date: "2025-12-26T16:00:00.000Z",
author: {
name: "Dominik Hladík",
email: "dominik.hladik@seznam.cz",
url: "https://github.com/Celtian",
},
git: {
branch: "master",
commit: "324822ac3893dd6159ab8cb4477d45edeacf11f6",
},
};
```

**Minimal Output (without author and git):**

```typescript
export const VERSION_INFO = {
version: "1.0.0",
date: "2025-12-26T16:00:00.000Z",
};
```

## 📖 Usage in Your Application

Once generated, import and use the version info in your application:

```typescript
import { VERSION_INFO } from "./version-info";

console.log(`Version: ${VERSION_INFO.version}`);
console.log(`Build Date: ${VERSION_INFO.date}`);

if (VERSION_INFO.author) {
console.log(`Author: ${VERSION_INFO.author.name}`);
console.log(`Email: ${VERSION_INFO.author.email}`);
console.log(`URL: ${VERSION_INFO.author.url}`);
}

if (VERSION_INFO.git) {
console.log(`Branch: ${VERSION_INFO.git.branch}`);
console.log(`Commit: ${VERSION_INFO.git.commit}`);
}
```

## 🔧 CLI Options

| Option | Alias | Default | Description |
| ----------- | ----- | ----------------- | ------------------------------ |
| `--version` | `-v` | - | Display version information |
| `--input` | `-i` | `package.json` | Path to package.json file |
| `--output` | `-o` | `version-info.ts` | Path to output TypeScript file |

## 🛠️ Integration with Build Tools

### NPM Scripts

Add to your `package.json`:

```json
{
"scripts": {
"prebuild": "package-version-info",
"build": "your-build-command"
}
}
```

### With TypeScript Projects

```json
{
"scripts": {
"version-info": "package-version-info --output src/version-info.ts",
"prebuild": "npm run version-info",
"build": "tsc"
}
}
```

## 🏗️ Development

This project is written in Zig. To build from source:

### Prerequisites

- [Zig](https://ziglang.org/) >= 0.15.2

### Build Commands

```bash
# Build the executable
zig build

# Run the executable
zig build run

# Run with arguments
zig build run -- --input package.json --output version-info.ts

# Run tests
zig build test

# Clean build artifacts
rm -rf zig-cache zig-out
```

## 🎯 Why Zig?

- **Performance**: Compiled binary with minimal overhead
- **Size**: Small executable footprint
- **Cross-platform**: Easy to build for multiple platforms
- **Memory Safety**: No runtime exceptions or undefined behavior

## 📦 Dependencies

_None_
_None_ - This is a standalone binary with zero runtime dependencies.

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## 🪪 License

Copyright © 2025 [Dominik Hladik](https://github.com/Celtian)

All contents are licensed under the [MIT license].

[mit license]: LICENSE
All contents are licensed under the [MIT license](LICENSE).
Loading