UNPKG

deepmerge-plus

Version:

用於深度(遞迴)合併 JavaScript 物件的函式庫 / A library for deep (recursive) merging of JavaScript objects

242 lines (174 loc) 6.06 kB
# ITmpRuntimeData 技術文件 # ITmpRuntimeData Technical Documentation ## 概述 `ITmpRuntimeData` deepmerge 庫中的一個內部執行時資料介面,用於在遞迴合併過程中追蹤上下文資訊。它記錄了當前合併操作的位置、路徑和相關物件引用。 `ITmpRuntimeData` is an internal runtime data interface in the deepmerge library, used to track context information during recursive merge operations. It records the current merge operation's position, path, and related object references. --- ## 類型定義 ### 核心介面 ```typescript export interface ITmpRuntimeData< T extends IAnyRecord = IAnyRecord, R extends IAnyRecord = IAnyRecord > { /** 遞迴深度計數(根為 0)/ Recursion depth count (root is 0) */ readonly level: number; /** 從根到目前位置的路徑陣列 / Path array from root to current position */ readonly paths: (keyof R | keyof T | ITSPropertyKey | number)[]; /** 最頂層的 destination 物件(永遠不變)/ Top-level destination object (always unchanged) */ readonly root: R; /** 目前層級的父物件 / Parent object at current level */ readonly parent: T; /** 目前正在處理的鍵名 / Key currently being processed */ readonly key: keyof T; } ``` ### 相關介面:ICache ```typescript export interface ICache { /** 鍵名 / Key name */ key? /** 來源物件 / Source object */ source? /** 目標物件 / Target object */ target? /** 目的物件 / Destination object */ destination? } ``` --- ## 核心概念 ### 1. 遞迴深度追蹤 (Level Tracking) 每次呼叫 `deepmerge` 遞迴時,`level` 會遞增: ``` 根層級: level = 0 第一層: level = 1 第二層: level = 2 ...以此類推 ``` ### 2. 路徑陣列 (Paths Array) `paths` 陣列記錄了從根物件到目前位置的完整路徑: ``` 合併 { a: { b: { c: 1 } } } 時: - 根層級: paths = [] - a: paths = ['a'] - b: paths = ['a', 'b'] - c: paths = ['a', 'b', 'c'] ``` ### 3. Root 永遠不變 `root` 指向最開始建立的 destination 物件,在整個遞迴過程中保持不變。這使得我們可以: - 使用 `_.get(root, paths)` 取得目前位置的物件 - 在任何層級都能取得最頂層的資料 ### 4. Key/Parent 關係 - `parent`: 目前層級的父物件 - `key`: 目前正在處理的鍵名 - 可透過 `parent[key]` 取得目前的值 --- ## 遞迴流程範例 ### 範例:合併巢狀物件 ```typescript const target = { level1: { level2: { value: 'original' } } }; const source = { level1: { level2: { value: 'updated', extra: 'data' } } }; merge(target, source); ``` ### 執行時序 | 階段 | level | paths | root | parent | key | |------|-------|-------|------|--------|-----| | 初始 | 0 | [] | {} | {} | undefined | | level1 | 1 | ['level1'] | {} | {} | 'level1' | | level2 | 2 | ['level1', 'level2'] | {} | {level1:{}} | 'level2' | | value | 3 | ['level1', 'level2', 'value'] | {} | {level1:{level2:{}}} | 'value' | --- ## ITmpRuntimeData 與 ICache 的差異 | 特性 | ITmpRuntimeData | ICache | |------|-----------------|--------| | 主要用途 | 追蹤遞迴路徑和深度 | 維護物件引用關係 | | 關注點 | **在哪裡** (位置) | **是什麼** (物件) | | 關鍵屬性 | level, paths, root | source, target, destination | | 變化頻率 | 每次遞迴都會變化 | 每次處理鍵值時會變化 | --- ## 使用場景 ### 1. 自訂 isMergeableObject 在自訂合併邏輯中,可以利用 `tmpRuntimeData` 取得目前位置資訊: ```typescript const options = { isMergeableObject: (value, defaultCheck, options, tmpRuntimeTarget, tmpRuntimeData) => { // 根據目前路徑決定是否可合併 if (tmpRuntimeData?.paths.includes('protected')) { return false; // protected 欄位不可合併 } return defaultCheck(value); } }; ``` ### 2. 自訂 arrayMerge 在自訂陣列合併策略中,可以使用 `tmpRuntimeData` 取得上下文: ```typescript const options = { arrayMerge: (target, source, options, tmpRuntimeData) => { console.log(`目前 level: ${tmpRuntimeData.level}`); console.log(`目前路徑: ${tmpRuntimeData.paths.join('.')}`); // 自訂合併邏輯... return [...target, ...source]; } }; ``` --- ## 測試驗證要點 根據 `test\tmp-runtime-data.test.ts`,以下 invariant 必須維持: ### 1. level 等於 paths.length ```typescript expect(tmpRuntimeData.level).toBe(tmpRuntimeData.paths.length); ``` ### 2. root 是最頂層物件 ```typescript // root 在所有巢狀層級中保持不變 expect(data.root).toBe(rootObject); ``` ### 3. 可使用 _.get(root, paths) 取得值 ```typescript const value = _.get(data.root, data.paths); expect(value).toBeDefined(); ``` ### 4. parent[key] 關係正確 ```typescript if (data.key !== undefined) { expect(data.parent[data.key]).toBeDefined(); } ``` --- ## 工具函數參考 ### test/lib/tmp-runtime-data.ts | 函數 | 用途 | |------|------| | `_createTmpRuntimeDataCapturer` | 建立自訂 isMergeableObject 來捕捉 tmpRuntimeData | | `_getValidTmpRuntimeData` | 過濾掉 undefined | | `_validateTmpRuntimeData` | 驗證單一 tmpRuntimeData 的正確性 | | `_validateAllTmpRuntimeData` | 批次驗證多個 tmpRuntimeData | | `_findByPath` | 按路徑條件查找 tmpRuntimeData | | `_filterByPathLength` | 按路徑長度篩選 tmpRuntimeData | --- ## 注意事項 1. **最深層可能為 undefined**:在最深層的 deepmerge 內,tmpRuntimeData 有可能是 undefined,這是正常行為。 2. **Root 可能是新物件**:deepmerge 內部會建立新的 destination 物件作為 root,這個物件會包含合併後的結果。 3. **僅供內部使用**:ITmpRuntimeData 是內部資料結構,主要用於讓自訂合併函式取得上下文資訊。 --- ## 相關檔案 - `src/index.ts` - 類型定義與主要邏輯 - `test/tmp-runtime-data.test.ts` - 測試檔案 - `test/lib/tmp-runtime-data.ts` - 測試工具函數