@charzing/vehicle-utils 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,130 +1,387 @@
1
1
  # @charzing/vehicle-utils
2
2
 
3
- Shared utilities for Charzing vehicle data management across all platforms.
3
+ Charzing 차량 데이터 관리를 위한 공유 유틸리티 라이브러리
4
4
 
5
- ## 설치
5
+ ## 📋 프로젝트 개요
6
+
7
+ **@charzing/vehicle-utils**는 Charzing 생태계의 모든 플랫폼(웹, 모바일, 관리자)에서 일관되게 사용할 수 있는 차량 데이터 변환 및 매핑 유틸리티를 제공합니다.
8
+
9
+ ### 주요 기능
10
+ - 🔄 브랜드/모델 ID 정규화 (한국어 ↔ 영어)
11
+ - 🖼️ Firebase Storage 차량 이미지 URL 생성
12
+ - 🏷️ 표준 파일명 생성 규칙
13
+ - 📦 TypeScript 완전 타입 지원
14
+
15
+ ---
16
+
17
+ ## 🛠️ 기술 스택
18
+
19
+ - **Language**: TypeScript 5
20
+ - **Build**: tsup (esbuild 기반)
21
+ - **Package Manager**: npm
22
+ - **Module**: ESM + CJS 모두 지원
23
+
24
+ ---
25
+
26
+ ## 📦 설치 방법
6
27
 
7
28
  ### 로컬 개발 (npm link)
8
29
 
9
30
  ```bash
31
+ # 1. vehicle-utils 빌드
10
32
  cd /Users/sungmin/charzing-vehicle-utils
11
33
  npm install
12
34
  npm run build
13
35
  npm link
14
36
 
15
- # 각 프로젝트에서
37
+ # 2. 각 프로젝트에서 링크
16
38
  cd /Users/sungmin/charzing-admin
17
39
  npm link @charzing/vehicle-utils
18
40
 
19
41
  cd /Users/sungmin/CharzingApp-Expo
20
42
  npm link @charzing/vehicle-utils
21
43
 
22
- cd /Users/sungmin/desktop/project/react/charzing
44
+ cd /Users/sungmin/Desktop/project/react/charzing
23
45
  npm link @charzing/vehicle-utils
24
46
  ```
25
47
 
26
- ## 주요 기능
48
+ ### npm 패키지로 설치 (프로덕션)
49
+
50
+ ```bash
51
+ npm install @charzing/vehicle-utils
52
+ ```
53
+
54
+ ---
55
+
56
+ ## 🚀 주요 API
27
57
 
28
58
  ### 1. 브랜드 매핑
29
59
 
60
+ #### `normalizeBrandId(brand: string): string`
61
+ 브랜드명을 표준 Firestore ID로 정규화합니다.
62
+
63
+ ```typescript
64
+ import { normalizeBrandId } from '@charzing/vehicle-utils';
65
+
66
+ // 한국어 → 영어 소문자
67
+ normalizeBrandId('현대'); // 'hyundai'
68
+ normalizeBrandId('기아'); // 'kia'
69
+ normalizeBrandId('테슬라'); // 'tesla'
70
+
71
+ // 대문자 유지 브랜드 (BMW, MINI, PORSCHE)
72
+ normalizeBrandId('BMW'); // 'bmw'
73
+ normalizeBrandId('MINI'); // 'mini'
74
+ normalizeBrandId('PORSCHE'); // 'porsche'
75
+
76
+ // 메르세데스-벤츠 처리
77
+ normalizeBrandId('메르세데스-벤츠'); // 'mercedes-benz'
78
+ normalizeBrandId('벤츠'); // 'mercedes-benz'
79
+ ```
80
+
81
+ #### `getBrandNameKorean(brandId: string): string`
82
+ Firestore ID로 한글 브랜드명을 가져옵니다.
83
+
30
84
  ```typescript
31
- import { normalizeBrandId, getBrandNameKorean, getBrandNameEnglish } from '@charzing/vehicle-utils';
85
+ import { getBrandNameKorean } from '@charzing/vehicle-utils';
86
+
87
+ getBrandNameKorean('hyundai'); // '현대'
88
+ getBrandNameKorean('mercedes-benz'); // '메르세데스-벤츠'
89
+ getBrandNameKorean('BMW'); // 'BMW'
90
+ ```
32
91
 
33
- // 브랜드 ID 정규화 (모두 소문자)
34
- const brandId = normalizeBrandId('현대'); // 'hyundai'
35
- const brandId2 = normalizeBrandId('BMW'); // 'bmw'
92
+ #### `getBrandNameEnglish(brandId: string): string`
93
+ Firestore ID로 영문 브랜드명을 가져옵니다.
36
94
 
37
- // 한글 브랜드명 가져오기
38
- const korean = getBrandNameKorean('hyundai'); // '현대'
95
+ ```typescript
96
+ import { getBrandNameEnglish } from '@charzing/vehicle-utils';
39
97
 
40
- // 영문 브랜드명 가져오기
41
- const english = getBrandNameEnglish('hyundai'); // 'HYUNDAI'
98
+ getBrandNameEnglish('hyundai'); // 'HYUNDAI'
99
+ getBrandNameEnglish('bmw'); // 'BMW'
100
+ getBrandNameEnglish('mini'); // 'MINI'
42
101
  ```
43
102
 
103
+ ---
104
+
44
105
  ### 2. 모델 매핑
45
106
 
107
+ #### `normalizeModelId(model: string): string`
108
+ 모델명을 표준 Firestore ID로 정규화합니다.
109
+
46
110
  ```typescript
47
- import { normalizeModelId, getModelNameKorean, getModelNameEnglish } from '@charzing/vehicle-utils';
111
+ import { normalizeModelId } from '@charzing/vehicle-utils';
48
112
 
49
- // 모델 ID 정규화 (소문자, 하이픈)
50
- const modelId = normalizeModelId('아이오닉 5'); // 'ioniq-5'
51
- const modelId2 = normalizeModelId('Model S'); // 'model-s'
113
+ // 한국어 영어 소문자
114
+ normalizeModelId('아이오닉 5'); // 'ioniq-5'
115
+ normalizeModelId('EV6'); // 'ev6'
116
+ normalizeModelId('Model S'); // 'model-s'
52
117
 
53
- // 한글 모델명 가져오기
54
- const korean = getModelNameKorean('ioniq-5'); // '아이오닉 5'
118
+ // 공백 하이픈 변환
119
+ normalizeModelId('쿠퍼'); // 'cooper'
120
+ normalizeModelId('Model 3'); // 'model-3'
121
+ ```
122
+
123
+ #### `getModelNameKorean(modelId: string): string`
124
+ Firestore ID로 한글 모델명을 가져옵니다.
55
125
 
56
- // 영문 모델명 가져오기
57
- const english = getModelNameEnglish('ioniq-5'); // 'IONIQ-5'
126
+ ```typescript
127
+ import { getModelNameKorean } from '@charzing/vehicle-utils';
128
+
129
+ getModelNameKorean('ioniq-5'); // '아이오닉 5'
130
+ getModelNameKorean('ev6'); // 'EV6'
131
+ getModelNameKorean('cooper'); // '쿠퍼'
58
132
  ```
59
133
 
134
+ #### `getModelNameEnglish(modelId: string): string`
135
+ Firestore ID로 영문 모델명을 가져옵니다.
136
+
137
+ ```typescript
138
+ import { getModelNameEnglish } from '@charzing/vehicle-utils';
139
+
140
+ getModelNameEnglish('ioniq-5'); // 'IONIQ-5'
141
+ getModelNameEnglish('model-s'); // 'MODEL-S'
142
+ ```
143
+
144
+ ---
145
+
60
146
  ### 3. 이미지 URL 생성
61
147
 
148
+ #### `generateVehicleImageUrl(params: ImageParams): string`
149
+ Firebase Storage 차량 이미지 URL을 생성합니다.
150
+
62
151
  ```typescript
63
- import { generateVehicleImageUrl, generateImageFilename } from '@charzing/vehicle-utils';
152
+ import { generateVehicleImageUrl } from '@charzing/vehicle-utils';
64
153
 
65
- // Firebase Storage URL 생성
66
- const imageUrl = generateVehicleImageUrl({
154
+ // 기본 이미지 (트림 없음)
155
+ const url1 = generateVehicleImageUrl({
67
156
  brand: 'hyundai',
68
157
  model: 'ioniq-5',
69
- year: 2024,
70
- trim: 'exclusive'
158
+ year: 2024
71
159
  });
72
160
  // → https://firebasestorage.googleapis.com/v0/b/charzing-d1600.firebasestorage.app/o/
73
- // vehicle-images%2FHYUNDAI%2FIONIQ-5%2F2024%2Fhyundai__ioniq-5__2024__exclusive.png?alt=media
74
-
75
- // 이미지 파일명만 생성
76
- const filename = generateImageFilename({
77
- brand: 'hyundai',
78
- model: 'ioniq-5',
79
- year: 2024,
80
- trim: 'exclusive'
161
+ // vehicle-images%2FHYUNDAI%2FIONIQ-5%2F2024%2Fhyundai__ioniq-5__2024.png?alt=media
162
+
163
+ // 트림별 이미지
164
+ const url2 = generateVehicleImageUrl({
165
+ brand: 'mini',
166
+ model: 'cooper',
167
+ year: 2025,
168
+ trim: 'jcw'
81
169
  });
82
- // → 'hyundai__ioniq-5__2024__exclusive.png'
170
+ // → https://firebasestorage.googleapis.com/v0/b/charzing-d1600.firebasestorage.app/o/
171
+ // vehicle-images%2FMINI%2FCOOPER%2F2025%2Fmini__cooper__2025__jcw.png?alt=media
172
+ ```
83
173
 
84
- // 트림 없는 경우
85
- const filename2 = generateImageFilename({
174
+ **파라미터**:
175
+ ```typescript
176
+ interface ImageParams {
177
+ brand: string; // 브랜드 ID (예: 'hyundai', 'bmw')
178
+ model: string; // 모델 ID (예: 'ioniq-5', 'model-s')
179
+ year: number; // 연도 (예: 2024)
180
+ trim?: string; // 트림 ID (선택, 예: 'exclusive', 'jcw')
181
+ }
182
+ ```
183
+
184
+ #### `generateImageFilename(params: ImageParams): string`
185
+ 이미지 파일명만 생성합니다.
186
+
187
+ ```typescript
188
+ import { generateImageFilename } from '@charzing/vehicle-utils';
189
+
190
+ // 기본 파일명
191
+ generateImageFilename({
86
192
  brand: 'tesla',
87
193
  model: 'model-s',
88
194
  year: 2024
89
195
  });
90
196
  // → 'tesla__model-s__2024.png'
197
+
198
+ // 트림 포함 파일명
199
+ generateImageFilename({
200
+ brand: 'porsche',
201
+ model: 'taycan',
202
+ year: 2025,
203
+ trim: 'turbo-gt'
204
+ });
205
+ // → 'porsche__taycan__2025__turbo-gt.png'
206
+ ```
207
+
208
+ ---
209
+
210
+ ## 📝 파일명 규칙
211
+
212
+ ### 표준 패턴
213
+ ```
214
+ {brandSlug}__{modelSlug}__{year}[__{trimSlug}].png
91
215
  ```
92
216
 
93
- ### 4. 파일명 규칙
217
+ ### 규칙
218
+ 1. **전부 소문자**: `hyundai`, `ioniq-5`
219
+ 2. **단어 구분**: 하이픈 (`-`)
220
+ 3. **상위 구분**: 더블 언더바 (`__`)
221
+ 4. **trim 없으면 생략**: `tesla__model-3__2024.png`
94
222
 
95
- - **패턴**: `{brandSlug}__{modelSlug}__{year}__{trimSlug}.png`
96
- - **예시**:
97
- - `hyundai__ioniq-5__2024.png`
98
- - `mini__cooper__2025__jcw.png`
99
- - `tesla__model-3__2024__highland.png`
100
- - **규칙**:
101
- - 전부 소문자
102
- - 단어 구분: 하이픈 (-)
103
- - 상위 구분: 더블 언더바 (__)
104
- - trim 없으면 생략
223
+ ### 예시
224
+ ```
225
+ hyundai__ioniq-5__2024.png
226
+ mini__cooper__2025__jcw.png
227
+ tesla__model-3__2024__highland.png
228
+ ✅ mercedes-benz__eqs__2024.png
229
+
230
+ ❌ Hyundai_ioniq-5_2024.png (대문자 사용)
231
+ ❌ hyundai-ioniq-5-2024.png (구분자 통일 안됨)
232
+ ❌ hyundai_ioniq-5_2024.png (단일 언더바)
233
+ ```
234
+
235
+ ---
236
+
237
+ ## 🏗️ 프로젝트 구조
238
+
239
+ ```
240
+ charzing-vehicle-utils/
241
+ ├── src/
242
+ │ ├── index.ts # 메인 엔트리포인트
243
+ │ ├── brand.ts # 브랜드 매핑 함수
244
+ │ ├── model.ts # 모델 매핑 함수
245
+ │ ├── image.ts # 이미지 URL 생성
246
+ │ └── types.ts # TypeScript 타입 정의
247
+ ├── dist/ # 빌드 결과물 (ESM + CJS)
248
+ ├── package.json
249
+ ├── tsconfig.json
250
+ └── tsup.config.ts # 빌드 설정
251
+ ```
105
252
 
106
- ## 개발
253
+ ---
254
+
255
+ ## 🔧 개발 가이드
256
+
257
+ ### 빌드 명령어
107
258
 
108
259
  ```bash
109
260
  # 의존성 설치
110
261
  npm install
111
262
 
112
- # 빌드
113
- npm run build
114
-
115
- # Watch 모드로 빌드
263
+ # 개발 모드 (Watch)
116
264
  npm run dev
117
265
 
118
- # 테스트
119
- npm test
266
+ # 프로덕션 빌드
267
+ npm run build
120
268
 
121
269
  # 타입 검사
122
270
  npm run type-check
123
271
 
124
272
  # 린트
125
273
  npm run lint
274
+
275
+ # 테스트
276
+ npm test
277
+ ```
278
+
279
+ ### 빌드 결과물
280
+
281
+ ```
282
+ dist/
283
+ ├── index.js # CommonJS (require)
284
+ ├── index.mjs # ESM (import)
285
+ ├── index.d.ts # TypeScript 타입 정의
286
+ └── index.d.mts # ESM 타입 정의
126
287
  ```
127
288
 
128
- ## 라이선스
289
+ ---
290
+
291
+ ## 🔄 업데이트 가이드
292
+
293
+ ### 로컬 개발 시
294
+ ```bash
295
+ # 1. vehicle-utils 수정 후 재빌드
296
+ cd /Users/sungmin/charzing-vehicle-utils
297
+ npm run build
298
+
299
+ # 2. 각 프로젝트는 자동 반영됨 (npm link로 연결되어 있음)
300
+ ```
301
+
302
+ ### 프로덕션 배포 시
303
+ ```bash
304
+ # 1. 버전 업데이트
305
+ npm version patch # 1.0.0 → 1.0.1
306
+
307
+ # 2. 빌드
308
+ npm run build
309
+
310
+ # 3. npm 배포
311
+ npm publish
312
+
313
+ # 4. 각 프로젝트에서 업데이트
314
+ cd /Users/sungmin/charzing-admin
315
+ npm update @charzing/vehicle-utils
316
+ ```
317
+
318
+ ---
319
+
320
+ ## 🔗 관련 프로젝트
321
+
322
+ 이 라이브러리를 사용하는 프로젝트들:
323
+
324
+ ### 1. **charzing-admin**
325
+ - **위치**: `/Users/sungmin/charzing-admin`
326
+ - **사용**: 차량 데이터 CRUD, 이미지 URL 생성
327
+ - **문서**: `/Users/sungmin/charzing-admin/CLAUDE.md`
328
+
329
+ ### 2. **CharzingApp-Expo**
330
+ - **위치**: `/Users/sungmin/CharzingApp-Expo`
331
+ - **사용**: 차량 선택, Firebase 데이터 조회
332
+ - **문서**: `/Users/sungmin/CharzingApp-Expo/CLAUDE.md`
333
+
334
+ ### 3. **charzing** (웹 앱)
335
+ - **위치**: `/Users/sungmin/Desktop/project/react/charzing`
336
+ - **사용**: 예약 시스템, 차량 이미지 표시
337
+ - **문서**: `/Users/sungmin/Desktop/project/react/charzing/CLAUDE.md`
338
+
339
+ ---
340
+
341
+ ## 📚 TypeScript 타입
342
+
343
+ 모든 함수는 완전한 TypeScript 타입 지원을 제공합니다.
344
+
345
+ ```typescript
346
+ // 브랜드 매핑
347
+ export function normalizeBrandId(brand: string): string;
348
+ export function getBrandNameKorean(brandId: string): string;
349
+ export function getBrandNameEnglish(brandId: string): string;
350
+
351
+ // 모델 매핑
352
+ export function normalizeModelId(model: string): string;
353
+ export function getModelNameKorean(modelId: string): string;
354
+ export function getModelNameEnglish(modelId: string): string;
355
+
356
+ // 이미지 URL 생성
357
+ export interface ImageParams {
358
+ brand: string;
359
+ model: string;
360
+ year: number;
361
+ trim?: string;
362
+ }
363
+
364
+ export function generateVehicleImageUrl(params: ImageParams): string;
365
+ export function generateImageFilename(params: ImageParams): string;
366
+ ```
367
+
368
+ ---
369
+
370
+ ## ⚠️ 주의사항
371
+
372
+ 1. **브랜드 대소문자**: BMW, MINI, PORSCHE는 Firestore에서 대문자 사용
373
+ 2. **Storage URL**: `charzing-d1600.firebasestorage.app` (`.appspot.com` ❌)
374
+ 3. **파일명 규칙**: 반드시 더블 언더바(`__`) 구분자 사용
375
+ 4. **npm link**: 로컬 개발 시 빌드 후 변경사항 자동 반영됨
376
+
377
+ ---
378
+
379
+ ## 📄 라이선스
129
380
 
130
381
  MIT
382
+
383
+ ---
384
+
385
+ **마지막 업데이트**: 2025년 12월 12일
386
+ **버전**: 0.2.4
387
+ **관리자**: Charzing 개발팀
@@ -1,4 +1,5 @@
1
1
  import { Firestore } from 'firebase/firestore';
2
+ export { CELL_MAP_UNSUPPORTED_GROUPS, CELL_MAP_UNSUPPORTED_NOTICE, CELL_VOLTAGE_DELTA_THRESHOLDS, CellMapReportRef, CellMapUnsupportedGroup, CellVoltageVerdict, findCellMapUnsupportedGroup, isCellMapSupported, judgeCellVoltageByDelta } from './report/cellMap.js';
2
3
 
3
4
  /**
4
5
  * 브랜드 관련 타입 정의
@@ -105,6 +106,15 @@ type TrimId = string;
105
106
  * 구동 방식
106
107
  */
107
108
  type DriveType = 'FWD' | 'RWD' | 'AWD' | '4WD';
109
+ /**
110
+ * 배터리 옵션 (복수 배터리 제조사 지원)
111
+ */
112
+ interface BatteryOption {
113
+ /** 배터리 제조사 */
114
+ supplier: string;
115
+ /** VIN 패턴, 생산 시기 등 조건 (선택사항) */
116
+ condition?: string;
117
+ }
108
118
  /**
109
119
  * 차량 변형 (연식별 스펙)
110
120
  */
@@ -115,8 +125,10 @@ interface VehicleVariant {
115
125
  batteryCapacity: number;
116
126
  /** 주행거리 (km) */
117
127
  range: number;
118
- /** 배터리 공급사 */
128
+ /** 배터리 공급사 (단일, 기존 호환) */
119
129
  supplier?: string;
130
+ /** 복수 배터리 공급사 (optional, supplier와 상호 배타적) */
131
+ batteryOptions?: BatteryOption[];
120
132
  /** 배터리 타입 */
121
133
  batteryType?: string;
122
134
  /** 이미지 URL (트림별 디자인 차이가 있는 경우) */
package/dist/cjs/index.js CHANGED
@@ -20,9 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ CELL_MAP_UNSUPPORTED_GROUPS: () => CELL_MAP_UNSUPPORTED_GROUPS,
24
+ CELL_MAP_UNSUPPORTED_NOTICE: () => CELL_MAP_UNSUPPORTED_NOTICE,
25
+ CELL_VOLTAGE_DELTA_THRESHOLDS: () => CELL_VOLTAGE_DELTA_THRESHOLDS,
23
26
  SUPPORTED_BRANDS: () => SUPPORTED_BRANDS,
24
27
  convertKoreanToEnglish: () => convertKoreanToEnglish,
25
28
  findBestModelMatch: () => findBestModelMatch,
29
+ findCellMapUnsupportedGroup: () => findCellMapUnsupportedGroup,
26
30
  generateImageFilename: () => generateImageFilename,
27
31
  generateStoragePath: () => generateStoragePath,
28
32
  generateVehicleImageUrl: () => generateVehicleImageUrl,
@@ -40,7 +44,9 @@ __export(index_exports, {
40
44
  initializeBrandMappings: () => initializeBrandMappings,
41
45
  initializeModelMappings: () => initializeModelMappings,
42
46
  isBrandMappingInitialized: () => isInitialized,
47
+ isCellMapSupported: () => isCellMapSupported,
43
48
  isModelMappingInitialized: () => isInitialized2,
49
+ judgeCellVoltageByDelta: () => judgeCellVoltageByDelta,
44
50
  normalizeBrandId: () => normalizeBrandId,
45
51
  normalizeModelId: () => normalizeModelId,
46
52
  resetBrandCache: () => resetCache,
@@ -473,11 +479,96 @@ function generateVehicleImageUrl(params) {
473
479
  const encodedPath = encodeURIComponent(path);
474
480
  return `${FIREBASE_STORAGE_BASE}/${encodedPath}?alt=media`;
475
481
  }
482
+
483
+ // src/report/cellMap.ts
484
+ var CELL_MAP_UNSUPPORTED_GROUPS = [
485
+ {
486
+ label: "MINI \uCFE0\uD37C SE (2022~2023)",
487
+ templateIds: ["YsOQDxElF5P0thuUHKhE"],
488
+ // vehicles/mini/models/COOPER — name: cooper-se_2022_2023
489
+ years: [2022, 2023],
490
+ names: {
491
+ brand: ["\uBBF8\uB2C8", "MINI", "Mini"],
492
+ model: ["\uCFE0\uD37C", "COOPER", "Cooper", "Cooper SE", "\uCFE0\uD37C SE"],
493
+ trim: ["SE"]
494
+ },
495
+ reason: "\uC9C4\uB2E8\uAE30\uAC00 \uBAA8\uB4C8\uBCC4 \uC804\uC555\uC744 \uB0B4\uB824\uC8FC\uC9C0 \uC54A\uC74C (min/max\uB9CC \uC81C\uACF5)"
496
+ }
497
+ ];
498
+ var CELL_MAP_UNSUPPORTED_NOTICE = {
499
+ /** 항상 노출 */
500
+ main: "\uC774 \uCC28\uB7C9\uC740 \uBAA8\uB4C8\uBCC4 \uC804\uC555\uC744 \uC81C\uACF5\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
501
+ /** min/max가 있을 때만 덧붙인다 — 없는 값을 있다고 말하지 않기 위해 */
502
+ sub: "\uCD5C\uC18C\xB7\uCD5C\uB300 \uC804\uC555\uB9CC \uCE21\uC815\uB429\uB2C8\uB2E4",
503
+ /** 어드민 수동 입력 화면에서 셀 입력을 잠글 때 */
504
+ inputLocked: "\uC774 \uCC28\uB7C9\uC740 \uBAA8\uB4C8\uBCC4 \uC804\uC555\uC744 \uC81C\uACF5\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uCD5C\uC18C\xB7\uCD5C\uB300 \uC804\uC555\uB9CC \uC785\uB825\uD558\uC138\uC694."
505
+ };
506
+ function normalizeName(value) {
507
+ return value.replace(/\s+/g, "").toLowerCase();
508
+ }
509
+ function matchesAnyName(value, candidates) {
510
+ if (!value) return false;
511
+ const target = normalizeName(value);
512
+ if (!target) return false;
513
+ return candidates.some((candidate) => normalizeName(candidate) === target);
514
+ }
515
+ function parseYear(value) {
516
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
517
+ if (typeof value === "string") {
518
+ const parsed = Number.parseInt(value, 10);
519
+ return Number.isNaN(parsed) ? null : parsed;
520
+ }
521
+ return null;
522
+ }
523
+ function readTemplateId(report) {
524
+ return report.marketplaceData?.vehicleRef?.templateId ?? report.vehicleRef?.templateId ?? null;
525
+ }
526
+ function findCellMapUnsupportedGroup(report) {
527
+ if (!report) return null;
528
+ const templateId = readTemplateId(report);
529
+ const year = parseYear(report.vehicleYear);
530
+ for (const group of CELL_MAP_UNSUPPORTED_GROUPS) {
531
+ if (templateId && group.templateIds.includes(templateId)) {
532
+ if (year === null || group.years.includes(year)) return group;
533
+ continue;
534
+ }
535
+ if (!templateId) {
536
+ const brandHit = matchesAnyName(report.vehicleBrand, group.names.brand);
537
+ const modelHit = matchesAnyName(report.vehicleModel, group.names.model);
538
+ const trimHit = group.names.trim === void 0 || group.names.trim.length === 0 ? true : matchesAnyName(report.vehicleTrim, group.names.trim);
539
+ const yearHit = year === null ? false : group.years.includes(year);
540
+ if (brandHit && modelHit && trimHit && yearHit) return group;
541
+ }
542
+ }
543
+ return null;
544
+ }
545
+ function isCellMapSupported(report) {
546
+ return findCellMapUnsupportedGroup(report) === null;
547
+ }
548
+ var CELL_VOLTAGE_DELTA_THRESHOLDS = {
549
+ warning: 0.03,
550
+ danger: 0.1
551
+ };
552
+ function round2(value) {
553
+ return Math.round(value * 100) / 100;
554
+ }
555
+ function judgeCellVoltageByDelta(minVoltage, maxVoltage) {
556
+ if (typeof minVoltage !== "number" || typeof maxVoltage !== "number") return null;
557
+ if (!Number.isFinite(minVoltage) || !Number.isFinite(maxVoltage)) return null;
558
+ const delta = round2(round2(maxVoltage) - round2(minVoltage));
559
+ if (delta >= CELL_VOLTAGE_DELTA_THRESHOLDS.danger) return "danger";
560
+ if (delta >= CELL_VOLTAGE_DELTA_THRESHOLDS.warning) return "warning";
561
+ return "normal";
562
+ }
476
563
  // Annotate the CommonJS export names for ESM import in node:
477
564
  0 && (module.exports = {
565
+ CELL_MAP_UNSUPPORTED_GROUPS,
566
+ CELL_MAP_UNSUPPORTED_NOTICE,
567
+ CELL_VOLTAGE_DELTA_THRESHOLDS,
478
568
  SUPPORTED_BRANDS,
479
569
  convertKoreanToEnglish,
480
570
  findBestModelMatch,
571
+ findCellMapUnsupportedGroup,
481
572
  generateImageFilename,
482
573
  generateStoragePath,
483
574
  generateVehicleImageUrl,
@@ -495,7 +586,9 @@ function generateVehicleImageUrl(params) {
495
586
  initializeBrandMappings,
496
587
  initializeModelMappings,
497
588
  isBrandMappingInitialized,
589
+ isCellMapSupported,
498
590
  isModelMappingInitialized,
591
+ judgeCellVoltageByDelta,
499
592
  normalizeBrandId,
500
593
  normalizeModelId,
501
594
  resetBrandCache,