npm package: @ooopenlab/quiz-shared
Description: Shared utilities and components for SuperQuiz modules
Author: OOOpen Lab
Latest version: 1.0.0

# 測驗共享程式庫

跨測驗系統使用的共享工具、常數和輔助函數。

## 概述

此程式庫包含在測驗系統不同部分間共享的通用工具、常數和輔助函數。它為可重複使用的程式碼提供了集中式位置。

## 工具

### ID 生成
```typescript
import { generateId } from '@ooopenlab/quiz-shared';

const quizId = generateId('quiz');     // quiz_1234567890_abc123def
const moduleId = generateId('module'); // module_1234567890_xyz789ghi
```

### 驗證輔助器
```typescript
import { isValidEmail, isValidUrl } from '@ooopenlab/quiz-shared';

const emailValid = isValidEmail('user@example.com'); // true
const urlValid = isValidUrl('https://example.com');  // true
```

### HTML 清理
```typescript
import { sanitizeHtml } from '@ooopenlab/quiz-shared';

const cleanHtml = sanitizeHtml('<p>Safe content</p><script>alert("xss")</script>');
// 回傳: '<p>Safe content</p>'
```

### 物件工具
```typescript
import { deepClone } from '@ooopenlab/quiz-shared';

const original = { quiz: { title: 'Test' } };
const copy = deepClone(original);
copy.quiz.title = 'New Title'; // original 保持不變
```

### 函數工具
```typescript
import { debounce, throttle } from '@ooopenlab/quiz-shared';

// 防抖 API 呼叫
const debouncedSave = debounce(saveQuiz, 300);

// 節流滾動事件
const throttledScroll = throttle(handleScroll, 100);
```

## 常數

### 測驗常數
```typescript
import { QUIZ_CONSTANTS } from '@ooopenlab/quiz-shared';

// 畫面類型
QUIZ_CONSTANTS.SCREEN_TYPES.COVER;    // 'cover'
QUIZ_CONSTANTS.SCREEN_TYPES.QUESTION; // 'question'
QUIZ_CONSTANTS.SCREEN_TYPES.RESULT;   // 'result'

// 路由
QUIZ_CONSTANTS.ROUTES.QUIZ_BASE;      // '/quiz/[quizId]'
QUIZ_CONSTANTS.ROUTES.QUIZ_QUESTION;  // '/quiz/[quizId]/question/[questionIndex]'
QUIZ_CONSTANTS.ROUTES.QUIZ_RESULT;    // '/quiz/[quizId]/result'

// 功能標誌
QUIZ_CONSTANTS.FEATURES.MULTI_QUESTIONS; // 'multiQuestions'
QUIZ_CONSTANTS.FEATURES.IS_FACTOR;       // 'isFactor'
QUIZ_CONSTANTS.FEATURES.SCORED_RESULT;   // 'scoredResult'
QUIZ_CONSTANTS.FEATURES.HAS_GEN_AI;      // 'hasGenAI'

// 預設值
QUIZ_CONSTANTS.DEFAULTS.MODULE_VERSION;   // '1.0.0'
QUIZ_CONSTANTS.DEFAULTS.TEXTAREA_ROWS;    // 4
QUIZ_CONSTANTS.DEFAULTS.MAX_FILE_SIZE;    // 5242880 (5MB)
QUIZ_CONSTANTS.DEFAULTS.DEBOUNCE_DELAY;   // 300ms
QUIZ_CONSTANTS.DEFAULTS.THROTTLE_LIMIT;   // 100ms

// 驗證規則
QUIZ_CONSTANTS.VALIDATION.MIN_PASSWORD_LENGTH; // 8
QUIZ_CONSTANTS.VALIDATION.MAX_TEXT_LENGTH;     // 1000
QUIZ_CONSTANTS.VALIDATION.MAX_TEXTAREA_LENGTH; // 5000
QUIZ_CONSTANTS.VALIDATION.MAX_FILE_COUNT;      // 10
```

### 類型定義
```typescript
import type { ScreenType, FeatureFlag } from '@ooopenlab/quiz-shared';

const screen: ScreenType = 'cover'; // 'cover' | 'question' | 'result'
const feature: FeatureFlag = 'multiQuestions'; // 有效的功能標誌
```

## API 參考

### 函數

| 函數 | 描述 | 參數 | 回傳值 |
|----------|-------------|------------|---------|
| `generateId(prefix?)` | 生成唯一 ID | `prefix: string` | `string` |
| `isValidEmail(email)` | 驗證電子郵件格式 | `email: string` | `boolean` |
| `isValidUrl(url)` | 驗證 URL 格式 | `url: string` | `boolean` |
| `sanitizeHtml(html)` | 移除危險的 HTML | `html: string` | `string` |
| `deepClone(obj)` | 深度複製物件 | `obj: T` | `T` |
| `debounce(func, wait)` | 防抖函數呼叫 | `func: Function, wait: number` | `Function` |
| `throttle(func, limit)` | 節流函數呼叫 | `func: Function, limit: number` | `Function` |

## 檔案結構

```
libs/quiz-shared/
├── src/
│   ├── utils.ts          # 工具函數
│   ├── constants.ts      # 常數和類型
│   └── index.ts          # 公開 API 匯出
├── project.json          # NX 專案設定
└── README.md            # 此檔案
```

## 依賴規則與循環依賴預防

### 架構分層
```
quiz-shared (基底層)
    ↑
quiz-form-fields (UI 層)
    ↑
quiz-modules (業務邏輯層)
```

### 依賴規則

1. **quiz-shared** (`type:util`)：
   - 🚫 **不可依賴任何其他 quiz 程式庫**
   - ✅ 只提供純工具函數、常數和類型定義
   - ✅ 可被其他所有程式庫使用

2. **其他程式庫對 quiz-shared 的使用**：
   - ✅ quiz-form-fields 可以使用 quiz-shared
   - ✅ quiz-modules 可以使用 quiz-shared
   - ✅ 應用程式可以直接使用 quiz-shared

### 防止循環依賴的檢查清單

- [ ] quiz-shared 中不包含任何 `import '@ooopenlab/quiz-*'`
- [ ] 新增功能時先檢查是否屬於基礎工具，應放在 quiz-shared
- [ ] 使用 `nx graph` 指令檢查依賴圖
- [ ] 利用 NX tags 進行依賴限制 (`"tags": ["scope:quiz", "type:util"]`)

## 在其他程式庫中的使用

```typescript
// 在 quiz-modules 中
import { QUIZ_CONSTANTS, generateId } from '@ooopenlab/quiz-shared';

// 在 quiz-form-fields 中
import { debounce, sanitizeHtml } from '@ooopenlab/quiz-shared';
```