このプロジェクトへの貢献を歓迎します!以下のガイドラインに従って、効果的で建設的な貢献を行ってください。
- 再現可能な手順を提供
- 期待される動作と実際の動作を明記
- 環境情報(OS、ブラウザ、バージョン)を含める
- 機能の目的と利点を説明
- 実装の詳細を検討
- 既存の機能との整合性を確認
- 不明瞭な部分の明確化
- 新しい例やチュートリアルの追加
- 翻訳の提供
- テストカバレッジの向上
- エッジケースのテスト追加
- パフォーマンステストの実装
# GitHubでリポジトリをフォーク
# ローカルにクローン
git clone https://github.com/your-username/sp_2506.git
cd sp_2506# バックエンド
cd jph-back-core
bun install
# フロントエンド
cd ../jph-front-core
bun installgit checkout -b feature/your-feature-name
# または
git checkout -b fix/your-bug-fix// 変数・関数: camelCase
const userName = 'john_doe';
const calculateTotal = () => {};
// クラス: PascalCase
class OPRFService {}
// 定数: UPPER_SNAKE_CASE
const MAX_RETRY_COUNT = 3;
// インターフェース: PascalCase with 'I' prefix
interface IUserData {}// 良い例
export const processUserData = async (
userId: string,
options: ProcessOptions
): Promise<ProcessResult> => {
// 実装
};
// 悪い例
export function processUserData(userId, options) {
// 実装
}// 良い例
try {
const result = await oprfService.processData(input);
return result;
} catch (error) {
logger.error('Failed to process data', error);
throw new ProcessingError('Data processing failed', { cause: error });
}
// 悪い例
const result = await oprfService.processData(input);
return result;// 良い例
interface UserProfileProps {
userId: string;
onUpdate?: (user: User) => void;
}
export const UserProfile: React.FC<UserProfileProps> = ({
userId,
onUpdate
}) => {
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]);
return (
<div className="user-profile">
{/* コンポーネントの内容 */}
</div>
);
};// カスタムフック
export const useUserData = (userId: string) => {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const fetchUser = async () => {
try {
setLoading(true);
const userData = await api.getUser(userId);
setUser(userData);
} catch (err) {
setError(err as Error);
} finally {
setLoading(false);
}
};
fetchUser();
}, [userId]);
return { user, loading, error };
};// tests/services/OPRFService.test.ts
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
import { OPRFService } from '../../src/services/OPRFService';
describe('OPRFService', () => {
let oprfService: OPRFService;
beforeEach(() => {
oprfService = new OPRFService('./secrets/test-key.priv');
});
afterEach(() => {
// クリーンアップ
});
describe('processData', () => {
it('should process valid input data', async () => {
// Arrange
const input = new TextEncoder().encode('test data');
// Act
const result = await oprfService.processData(input);
// Assert
expect(result).toBeDefined();
expect(result.length).toBeGreaterThan(0);
});
it('should throw error for invalid input', async () => {
// Arrange
const invalidInput = null as any;
// Act & Assert
await expect(oprfService.processData(invalidInput))
.rejects
.toThrow('Invalid input data');
});
});
});// src/components/__tests__/UserProfile.test.tsx
import { describe, it, expect, vi } from 'bun:test';
import { render, screen, waitFor } from '@testing-library/react';
import { UserProfile } from '../UserProfile';
// モック
vi.mock('../../hooks/useUserData', () => ({
useUserData: vi.fn()
}));
describe('UserProfile', () => {
it('renders user information correctly', async () => {
// Arrange
const mockUser = { id: '1', name: 'John Doe', email: 'john@example.com' };
const { useUserData } = await import('../../hooks/useUserData');
vi.mocked(useUserData).mockReturnValue({
user: mockUser,
loading: false,
error: null
});
// Act
render(<UserProfile userId="1" />);
// Assert
await waitFor(() => {
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('john@example.com')).toBeInTheDocument();
});
});
});// tests/integration/api.test.ts
import { describe, it, expect, beforeAll, afterAll } from 'bun:test';
import request from 'supertest';
import { app } from '../../src/app';
describe('API Integration Tests', () => {
beforeAll(async () => {
// テストサーバーの起動
});
afterAll(async () => {
// テストサーバーの停止
});
describe('POST /upload-binary', () => {
it('should process binary data successfully', async () => {
const testData = Buffer.from('test binary data');
const response = await request(app)
.post('/upload-binary')
.send(testData)
.expect(200);
expect(response.body).toBeDefined();
});
});
});# 最新のmainブランチを取得
git checkout main
git pull origin main
# 新しいブランチを作成
git checkout -b feature/your-feature-name# 変更をコミット
git add .
git commit -m "feat: add new OPRF endpoint"
# ブランチをプッシュ
git push origin feature/your-feature-name## 変更内容
- 変更の概要を記述
## 変更の種類
- [ ] バグ修正
- [ ] 新機能
- [ ] 破壊的変更
- [ ] ドキュメント更新
## テスト
- [ ] 単体テストを追加/更新
- [ ] 統合テストを追加/更新
- [ ] 手動テストを実行
## チェックリスト
- [ ] コードがプロジェクトのコーディング規約に従っている
- [ ] 自己レビューを実行した
- [ ] コメントを追加した(特に理解しにくい部分)
- [ ] 対応するドキュメントを更新した
- [ ] 変更が既存の機能を壊していない- コードが要件を満たしている
- エッジケースが適切に処理されている
- エラーハンドリングが適切
- コードが読みやすい
- 適切な命名がされている
- 重複コードがない
- 適切な抽象化レベル
- パフォーマンスに問題がない
- メモリリークがない
- 適切なキャッシュ戦略
- セキュリティホールがない
- 入力検証が適切
- 機密情報の漏洩がない
/**
* OPRFプロトコルを使用してデータを処理します
*
* @param input - 処理するバイナリデータ
* @param options - 処理オプション
* @returns 処理済みのバイナリデータ
* @throws {InvalidInputError} 入力データが無効な場合
* @throws {OPRFError} OPRF処理中にエラーが発生した場合
*/
export const processData = async (
input: Uint8Array,
options: ProcessOptions
): Promise<Uint8Array> => {
// 入力データの検証
if (!input || input.length === 0) {
throw new InvalidInputError('Input data cannot be empty');
}
// OPRF処理の実行
// 注意: この処理は暗号学的に安全でなければならない
const result = await oprfService.process(input);
return result;
};// データを処理する
export const processData = (input) => {
// 処理
return result;
};- メジャー: 破壊的変更
- マイナー: 新機能追加
- パッチ: バグ修正
- バージョン番号の更新
- CHANGELOGの更新
- タグの作成
- リリースノートの作成
- GitHub Issues: バグ報告、機能要望
- GitHub Discussions: 一般的な質問、議論
- Pull Request: コードレビュー中の質問
## 環境
- OS: macOS 13.0
- Bun: 1.0.0
- Node.js: 18.17.0
## 問題の説明
具体的に何が起こっているかを説明
## 期待される動作
何が起こるべきかを説明
## 実際の動作
何が起こっているかを説明
## 再現手順
1. 手順1
2. 手順2
3. 手順3
## 追加情報
ログ、スクリーンショット、関連するIssueなど貢献者として認められる条件:
- 有効なプルリクエストのマージ
- ドキュメントの改善
- バグレポートの提供
- コミュニティでの支援
このプロジェクトはMITライセンスの下で公開されています。貢献するコードも同じライセンスの下で公開されることに同意してください。
ありがとうございます! このプロジェクトへの貢献を心より歓迎します。質問や提案があれば、お気軽にお声がけください。