feat(ground): accept ground_model.json written before the schema number
- A file with no `schema` key is read as schema 1, but every pier must have a `ground` object, so a renamed field is refused instead of loading as empty. - `schema` null or any other number is still refused. - The project file keeps the normalised model and checks it with its own check (checkStoredGroundModel), so a saved model reopens. - Temporary: remove the no-schema branch once examples/out is regenerated. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c3606011b5
commit
be76425c8f
4 files changed
+453
-6
No files matched your search
@@ -25,21 +25,44 @@ 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. */
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
export function checkGroundModel(raw: unknown): GroundModelFile {
|
||||
const obj = raw as Partial<GroundModelFile> | null;
|
||||
if (!obj || typeof obj !== 'object') throw new Error('지반 모델 파일 형식이 아닙니다.');
|
||||
if (obj.schema !== GROUND_MODEL_SCHEMA) {
|
||||
if (obj.schema !== undefined && obj.schema !== GROUND_MODEL_SCHEMA) {
|
||||
throw new Error(`지반 모델 형식 번호 ${String(obj.schema)}을(를) 읽을 수 없습니다 (지원: ${GROUND_MODEL_SCHEMA}).`);
|
||||
}
|
||||
if (!Array.isArray(obj.piers)) throw new Error('지반 모델 파일에 교각 목록(piers)이 없습니다.');
|
||||
const piers = obj.piers.map((p, i) => {
|
||||
const id = (p as { id?: unknown })?.id;
|
||||
if (typeof id !== 'string' || !id) throw new Error(`지반 모델 ${i + 1}번째 교각의 이름(id)이 없습니다.`);
|
||||
const ground = (p as { ground?: { center?: unknown; excel?: unknown } }).ground ?? {};
|
||||
const ground = (p as { ground?: { center?: unknown; excel?: unknown } }).ground;
|
||||
if (!ground || typeof ground !== 'object') throw new Error(`지반 모델 ${id}: 지반 값(ground)이 없습니다.`);
|
||||
return { id, centerEl: numOrNull(ground.center), excelEl: numOrNull(ground.excel) };
|
||||
});
|
||||
return { schema: obj.schema, generated: typeof obj.generated === 'string' ? obj.generated : '', piers };
|
||||
return { schema: GROUND_MODEL_SCHEMA, generated: typeof obj.generated === 'string' ? obj.generated : '', piers };
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the normalised model stored in a project file (the form checkGroundModel returns). The project keeps this
|
||||
* form, not the raw ground_model.json, so it is checked separately.
|
||||
*/
|
||||
export function checkStoredGroundModel(raw: unknown): GroundModelFile {
|
||||
const obj = raw as Partial<GroundModelFile> | null;
|
||||
if (!obj || typeof obj !== 'object' || obj.schema !== GROUND_MODEL_SCHEMA) {
|
||||
throw new Error('프로젝트 안의 지반 모델 형식 번호가 맞지 않습니다.');
|
||||
}
|
||||
if (!Array.isArray(obj.piers)) throw new Error('프로젝트 안의 지반 모델에 교각 목록이 없습니다.');
|
||||
for (const p of obj.piers as Partial<GroundModelPier>[]) {
|
||||
const ok = typeof p?.id === 'string' && (p.centerEl === null || typeof p.centerEl === 'number') && (p.excelEl === null || typeof p.excelEl === 'number');
|
||||
if (!ok) throw new Error(`프로젝트 안의 지반 모델 교각 ${String(p?.id)}의 값이 맞지 않습니다.`);
|
||||
}
|
||||
return obj as GroundModelFile;
|
||||
}
|
||||
|
||||
/** Parses the file text. Throws when it is not JSON or does not match the schema. */
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import type { FckByMember, Material } from './rebar/common';
|
||||
import { checkGroundModel, type GroundModelFile } from './ground-model';
|
||||
import { checkStoredGroundModel, type GroundModelFile } from './ground-model';
|
||||
import type { PierInput } from './types';
|
||||
|
||||
/** Project file schema (spec §8). Bump only with a migration. */
|
||||
@@ -71,7 +71,7 @@ export function parseProject(text: string): ProjectFile {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (obj.groundModel !== undefined) checkGroundModel(obj.groundModel);
|
||||
if (obj.groundModel !== undefined) checkStoredGroundModel(obj.groundModel);
|
||||
obj.piers.forEach((p, i) => {
|
||||
if (!p || typeof p.id !== 'string' || !p.input) throw new Error(`교각 ${i + 1}: id 또는 input이 없습니다.`);
|
||||
const input = p.input;
|
||||
|
||||
Reference in new issue
Block a user