refactor(ground): remove the unversioned-file fallback
- A file without a schema number is refused again; the example output in RAG/pierzainer_ground now has schema 2, so the temporary path is not needed. - The legacy fixture is removed; tests cover the missing and null schema numbers and a pier without a ground object. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bfd41d7c8d
commit
0e70cfb969
3 files changed
+9
-417
No files matched your search
@@ -37,16 +37,11 @@ function numOrNull(v: unknown): number | null {
|
||||
return typeof v === 'number' && Number.isFinite(v) ? v : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the shape of a parsed ground_model.json. Throws with the first problem named in Korean.
|
||||
* A file with no `schema` key is the layout written before the number was added: it is read as schema 1, and the
|
||||
* `ground` object is required so that a renamed field is refused instead of loading as empty values.
|
||||
* TODO: remove the no-schema branch once the 옛 파일 (examples/out) is regenerated with schema 1.
|
||||
*/
|
||||
/** Checks the shape of a parsed ground_model.json. Throws with the first problem named in Korean. */
|
||||
export function checkGroundModel(raw: unknown): GroundModelFile {
|
||||
const obj = raw as Partial<GroundModelFile> | null;
|
||||
if (!obj || typeof obj !== 'object') throw new Error('지반 모델 파일 형식이 아닙니다.');
|
||||
if (obj.schema !== undefined && !READABLE_SCHEMAS.includes(obj.schema)) {
|
||||
if (!READABLE_SCHEMAS.includes(obj.schema as number)) {
|
||||
throw new Error(`지반 모델 형식 번호 ${String(obj.schema)}을(를) 읽을 수 없습니다 (지원: ${READABLE_SCHEMAS.join(', ')}).`);
|
||||
}
|
||||
if (!Array.isArray(obj.piers)) throw new Error('지반 모델 파일에 교각 목록(piers)이 없습니다.');
|
||||
|
||||
-393
@@ -1,393 +0,0 @@
|
||||
{
|
||||
"generated": "2026-10-23",
|
||||
"coord": "측량 X(북) · Y(동), m. 치수 mm",
|
||||
"terrain": {
|
||||
"file": "C0050202-001.dxf",
|
||||
"spot_blocks": 433,
|
||||
"spot_texts": 190,
|
||||
"contours": 67,
|
||||
"line3d_vertices": 0,
|
||||
"points_used": 3429,
|
||||
"by_source": {
|
||||
"spot": 431,
|
||||
"text": 5,
|
||||
"contour": 2993,
|
||||
"line3d": 0
|
||||
},
|
||||
"removed": 1,
|
||||
"boreholes": 18,
|
||||
"extent": [
|
||||
259779.6342279386,
|
||||
179066.3432863709,
|
||||
260208.0132279157,
|
||||
179261.3784074617
|
||||
]
|
||||
},
|
||||
"removed_points": [
|
||||
{
|
||||
"X": 260155.762358268,
|
||||
"Y": 179189.228890184,
|
||||
"Z": -18.115,
|
||||
"source": "spot",
|
||||
"reason": "EL 범위 밖 (0.0–200.0)"
|
||||
}
|
||||
],
|
||||
"boreholes_dxf": [
|
||||
{
|
||||
"id": "BB-24",
|
||||
"X": 260110.5200305235,
|
||||
"Y": 179142.87077588285
|
||||
},
|
||||
{
|
||||
"id": "BB-28",
|
||||
"X": 259832.7395636612,
|
||||
"Y": 179078.6772609205
|
||||
},
|
||||
{
|
||||
"id": "NBB-21",
|
||||
"X": 260169.7415555437,
|
||||
"Y": 179217.2592038325
|
||||
},
|
||||
{
|
||||
"id": "NBB-22",
|
||||
"X": 260119.0843895569,
|
||||
"Y": 179207.447663092
|
||||
},
|
||||
{
|
||||
"id": "NBB-23",
|
||||
"X": 260063.7209158014,
|
||||
"Y": 179200.7170868495
|
||||
},
|
||||
{
|
||||
"id": "NBB-24",
|
||||
"X": 260013.7365954409,
|
||||
"Y": 179193.2691158374
|
||||
},
|
||||
{
|
||||
"id": "NBB-25",
|
||||
"X": 259959.8230206913,
|
||||
"Y": 179182.585023065
|
||||
},
|
||||
{
|
||||
"id": "NBB-26",
|
||||
"X": 259908.1691879086,
|
||||
"Y": 179170.4141072329
|
||||
},
|
||||
{
|
||||
"id": "NBB-27",
|
||||
"X": 259862.0303893618,
|
||||
"Y": 179162.6491102049
|
||||
},
|
||||
{
|
||||
"id": "NBB-28",
|
||||
"X": 259804.6978413376,
|
||||
"Y": 179143.6022597326
|
||||
},
|
||||
{
|
||||
"id": "NBB-29",
|
||||
"X": 260162.3349768046,
|
||||
"Y": 179177.2095564581
|
||||
},
|
||||
{
|
||||
"id": "NBB-30",
|
||||
"X": 260115.11201831407,
|
||||
"Y": 179163.3224655297
|
||||
},
|
||||
{
|
||||
"id": "NBB-31",
|
||||
"X": 260052.92384203407,
|
||||
"Y": 179154.4466218247
|
||||
},
|
||||
{
|
||||
"id": "NBB-32",
|
||||
"X": 260004.4464295526,
|
||||
"Y": 179155.3905176037
|
||||
},
|
||||
{
|
||||
"id": "NBB-33",
|
||||
"X": 259953.9248062317,
|
||||
"Y": 179147.6435384383
|
||||
},
|
||||
{
|
||||
"id": "NBB-34",
|
||||
"X": 259903.7958026133,
|
||||
"Y": 179135.2767765673
|
||||
},
|
||||
{
|
||||
"id": "NBB-35",
|
||||
"X": 259855.9217242609,
|
||||
"Y": 179124.5131579286
|
||||
},
|
||||
{
|
||||
"id": "NBB-36",
|
||||
"X": 259804.9274191266,
|
||||
"Y": 179111.1866481418
|
||||
}
|
||||
],
|
||||
"borehole_issues": [],
|
||||
"piers": [
|
||||
{
|
||||
"id": "P1",
|
||||
"X": 259865.676,
|
||||
"Y": 179138.094,
|
||||
"axis_dir": [
|
||||
0.16722,
|
||||
-0.98592
|
||||
],
|
||||
"ground": {
|
||||
"center": 29.355,
|
||||
"corners": [
|
||||
29.536,
|
||||
29.441,
|
||||
29.18,
|
||||
29.27
|
||||
],
|
||||
"min": 29.18,
|
||||
"max": 29.536,
|
||||
"used": 29.355,
|
||||
"source": "계산",
|
||||
"dtm_spacing": 19.0,
|
||||
"excel": 28.931,
|
||||
"diff_vs_excel": 0.424
|
||||
},
|
||||
"footing": {
|
||||
"L_mm": 10400.0,
|
||||
"W_mm": 8150.0,
|
||||
"top_el": 28.208,
|
||||
"bottom_el": 26.208,
|
||||
"cover": 0.972
|
||||
},
|
||||
"pile": {
|
||||
"tip_el": 2.208,
|
||||
"d_mm": 609.6
|
||||
},
|
||||
"soil": null,
|
||||
"alerts": [
|
||||
{
|
||||
"code": "W09",
|
||||
"level": "경고",
|
||||
"pier": "P1",
|
||||
"message": "엑셀 지반고 28.931와 지형 29.355의 차이 +0.424 m가 허용 0.3 m를 넘습니다."
|
||||
},
|
||||
{
|
||||
"code": "I05",
|
||||
"level": "정보",
|
||||
"pier": "P1",
|
||||
"message": "시추 자료가 없어 지층을 판정하지 않았습니다."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "P2",
|
||||
"X": 259914.439,
|
||||
"Y": 179149.112,
|
||||
"axis_dir": [
|
||||
0.167151,
|
||||
-0.985931
|
||||
],
|
||||
"ground": {
|
||||
"center": 28.167,
|
||||
"corners": [],
|
||||
"min": 28.167,
|
||||
"max": 28.167,
|
||||
"used": 28.167,
|
||||
"source": "계산",
|
||||
"dtm_spacing": 19.5,
|
||||
"excel": null,
|
||||
"diff_vs_excel": null
|
||||
},
|
||||
"footing": {
|
||||
"L_mm": null,
|
||||
"W_mm": null,
|
||||
"top_el": null,
|
||||
"bottom_el": null,
|
||||
"cover": null
|
||||
},
|
||||
"pile": {
|
||||
"tip_el": null,
|
||||
"d_mm": null
|
||||
},
|
||||
"soil": null,
|
||||
"alerts": [
|
||||
{
|
||||
"code": "I05",
|
||||
"level": "정보",
|
||||
"pier": "P2",
|
||||
"message": "시추 자료가 없어 지층을 판정하지 않았습니다."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "P3",
|
||||
"X": 259963.44,
|
||||
"Y": 179159.017,
|
||||
"axis_dir": [
|
||||
0.167117,
|
||||
-0.985937
|
||||
],
|
||||
"ground": {
|
||||
"center": 28.12,
|
||||
"corners": [],
|
||||
"min": 28.12,
|
||||
"max": 28.12,
|
||||
"used": 28.12,
|
||||
"source": "계산",
|
||||
"dtm_spacing": 48.6,
|
||||
"excel": null,
|
||||
"diff_vs_excel": null
|
||||
},
|
||||
"footing": {
|
||||
"L_mm": null,
|
||||
"W_mm": null,
|
||||
"top_el": null,
|
||||
"bottom_el": null,
|
||||
"cover": null
|
||||
},
|
||||
"pile": {
|
||||
"tip_el": null,
|
||||
"d_mm": null
|
||||
},
|
||||
"soil": null,
|
||||
"alerts": [
|
||||
{
|
||||
"code": "I07",
|
||||
"level": "정보",
|
||||
"pier": "P3",
|
||||
"message": "지반고를 만든 지형 점이 최대 48.6 m 떨어져 있습니다 (기준 30 m). 현장 측량값을 확인하세요."
|
||||
},
|
||||
{
|
||||
"code": "I05",
|
||||
"level": "정보",
|
||||
"pier": "P3",
|
||||
"message": "시추 자료가 없어 지층을 판정하지 않았습니다."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "P4",
|
||||
"X": 260012.654,
|
||||
"Y": 179167.802,
|
||||
"axis_dir": [
|
||||
0.167117,
|
||||
-0.985937
|
||||
],
|
||||
"ground": {
|
||||
"center": 28.608,
|
||||
"corners": [],
|
||||
"min": 28.608,
|
||||
"max": 28.608,
|
||||
"used": 28.608,
|
||||
"source": "계산",
|
||||
"dtm_spacing": 44.3,
|
||||
"excel": null,
|
||||
"diff_vs_excel": null
|
||||
},
|
||||
"footing": {
|
||||
"L_mm": null,
|
||||
"W_mm": null,
|
||||
"top_el": null,
|
||||
"bottom_el": null,
|
||||
"cover": null
|
||||
},
|
||||
"pile": {
|
||||
"tip_el": null,
|
||||
"d_mm": null
|
||||
},
|
||||
"soil": null,
|
||||
"alerts": [
|
||||
{
|
||||
"code": "I07",
|
||||
"level": "정보",
|
||||
"pier": "P4",
|
||||
"message": "지반고를 만든 지형 점이 최대 44.3 m 떨어져 있습니다 (기준 30 m). 현장 측량값을 확인하세요."
|
||||
},
|
||||
{
|
||||
"code": "I05",
|
||||
"level": "정보",
|
||||
"pier": "P4",
|
||||
"message": "시추 자료가 없어 지층을 판정하지 않았습니다."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "P5",
|
||||
"X": 260062.055,
|
||||
"Y": 179175.464,
|
||||
"axis_dir": [
|
||||
0.1671,
|
||||
-0.98594
|
||||
],
|
||||
"ground": {
|
||||
"center": 27.242,
|
||||
"corners": [],
|
||||
"min": 27.242,
|
||||
"max": 27.242,
|
||||
"used": 27.242,
|
||||
"source": "계산",
|
||||
"dtm_spacing": 2.7,
|
||||
"excel": null,
|
||||
"diff_vs_excel": null
|
||||
},
|
||||
"footing": {
|
||||
"L_mm": null,
|
||||
"W_mm": null,
|
||||
"top_el": null,
|
||||
"bottom_el": null,
|
||||
"cover": null
|
||||
},
|
||||
"pile": {
|
||||
"tip_el": null,
|
||||
"d_mm": null
|
||||
},
|
||||
"soil": null,
|
||||
"alerts": [
|
||||
{
|
||||
"code": "I05",
|
||||
"level": "정보",
|
||||
"pier": "P5",
|
||||
"message": "시추 자료가 없어 지층을 판정하지 않았습니다."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "P6",
|
||||
"X": 260116.582,
|
||||
"Y": 179182.59,
|
||||
"axis_dir": [
|
||||
0.167062,
|
||||
-0.985946
|
||||
],
|
||||
"ground": {
|
||||
"center": 28.766,
|
||||
"corners": [],
|
||||
"min": 28.766,
|
||||
"max": 28.766,
|
||||
"used": 28.766,
|
||||
"source": "계산",
|
||||
"dtm_spacing": 14.3,
|
||||
"excel": null,
|
||||
"diff_vs_excel": null
|
||||
},
|
||||
"footing": {
|
||||
"L_mm": null,
|
||||
"W_mm": null,
|
||||
"top_el": null,
|
||||
"bottom_el": null,
|
||||
"cover": null
|
||||
},
|
||||
"pile": {
|
||||
"tip_el": null,
|
||||
"d_mm": null
|
||||
},
|
||||
"soil": null,
|
||||
"alerts": [
|
||||
{
|
||||
"code": "I05",
|
||||
"level": "정보",
|
||||
"pier": "P6",
|
||||
"message": "시추 자료가 없어 지층을 판정하지 않았습니다."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { groundElFor, parseGroundModel } from '../src/core/ground-model';
|
||||
import { changedKeys, overrideKeys, revertDraft, type PierValues } from '../src/core/changes';
|
||||
@@ -89,26 +88,17 @@ describe('지형 격자 (schema 2)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('번호 없는 옛 지반 모델 (B′: 임시 경로)', () => {
|
||||
// examples/out/ground_model.json as written before the schema number existed (P1–P6, same values as the report).
|
||||
const LEGACY = readFileSync(new URL('./fixtures/ground-model-legacy.json', import.meta.url), 'utf-8');
|
||||
|
||||
it('reads the unversioned file and reports it as schema 1', () => {
|
||||
const m = parseGroundModel(LEGACY);
|
||||
expect(m.schema).toBe(2); // normalised to the current schema
|
||||
expect(m.piers.map((p) => p.id)).toEqual(['P1', 'P2', 'P3', 'P4', 'P5', 'P6']);
|
||||
expect(groundElFor(m, 'P1')).toBe(29.355);
|
||||
expect(m.piers[0].excelEl).toBe(28.931);
|
||||
describe('형식 번호 검사', () => {
|
||||
it('refuses a file with no schema number (the B′ fallback is removed)', () => {
|
||||
expect(() => parseGroundModel(JSON.stringify({ piers: [{ id: 'P1', ground: { center: 29.355, excel: 28.931 } }] }))).toThrow('형식 번호 undefined');
|
||||
});
|
||||
|
||||
it('refuses a pier that has no ground object (a renamed field must not load as empty values)', () => {
|
||||
const data = JSON.parse(LEGACY);
|
||||
delete data.piers[1].ground;
|
||||
expect(() => parseGroundModel(JSON.stringify(data))).toThrow('P2: 지반 값(ground)이 없습니다');
|
||||
it('refuses a null schema number', () => {
|
||||
expect(() => parseGroundModel('{"schema": null, "piers": []}')).toThrow('형식 번호 null');
|
||||
});
|
||||
|
||||
it('refuses a null schema number instead of treating it as missing', () => {
|
||||
expect(() => parseGroundModel(LEGACY.replace('{', '{"schema": null,'))).toThrow('형식 번호 null');
|
||||
it('refuses a pier that has no ground object', () => {
|
||||
expect(() => parseGroundModel(JSON.stringify({ schema: 1, piers: [{ id: 'P2' }] }))).toThrow('P2: 지반 값(ground)이 없습니다');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user