@g1cloud/entity-modeler-next 5.2.38 → 5.2.39

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.
@@ -315,6 +315,10 @@ export type ResolveError = {
315
315
  * 논리명 축이 없어 **열린 문(dotted) 옆에서 막힌 문을 가리키고** 있었다(실사용에서 raw `/ops` 우회를
316
316
  * 유발했다 — 불필요했다). dotted 는 아래 `attribute-patch-unknown-key` 가 이미 허용하는 접두다.
317
317
  * - **dbAttrs 0개** → `fieldLogicalName`(아래 주석 — 이쪽은 처음부터 대안을 지목하고 있었다).
318
+ * - ★**`attrType !== 'NORMAL'`**(FK 파생 `RELATION_*`·임베드·직렬화 타입) → **dotted**. ⚠️이 갈래는
319
+ * 종전 서술에 «없었다** — 위 두 줄이 사유를 「다중 컬럼」·「0컬럼」으로만 적어서 **단일 컬럼 FK** 가
320
+ * 걸릴 때 안내가 EMBED 축을 가리켰다(2026-09-08 · FK 가드 회차에서 드러났다). 매핑을 열지 않는 이유는
321
+ * 모호성이 아니라 **경로를 하나로 두는 것**이다 — dotted 가 이미 그 자리를 정확히 지목한다.
318
322
  */
319
323
  | {
320
324
  code: 'attribute-patch-dbattr-flat-key';
@@ -399,6 +403,21 @@ export type ResolveError = {
399
403
  opIndex: number;
400
404
  keys: string[];
401
405
  }
406
+ /**
407
+ * ★**계열의 «중첩» 사본** — 위 여섯은 spec 의 **1단 키**만 보는데 `embeddableOverrides` 는 spec 안의
408
+ * **배열**이고 그 items 의 키는 add·update 양쪽에서 아무도 안 봤다(`ATTR_SPEC_KEYS` 에 배열 «이름»만
409
+ * 있다). resolver 가 `field` 로 매칭해 명명된 필드만 읽으므로 미지 키는 **조용히 사라진다** —
410
+ * 실측 `{field:'amount', dataType:'NUMERIC'}` 이 `ok:true` 인데 `dataType` 이 소실됐다.
411
+ * ⇒ 계열의 근거(*「무신호 소실」* + *「스키마가 이미 `additionalProperties:false` 로 닫아 둔 계약의
412
+ * 집행」*)가 **그대로** 적용된다 · 스키마 자리는 `EMBEDDABLE_OVERRIDES.items`.
413
+ */
414
+ | {
415
+ code: 'embeddable-override-unknown-key';
416
+ opIndex: number;
417
+ entity: Handle;
418
+ handle: Handle;
419
+ keys: string[];
420
+ }
402
421
  /**
403
422
  * entity.add의 논리명이 모델에 이미 있는 엔티티와 충돌. 통과시키면 **도구가 스스로 `CHK-NAME-3`(error)
404
423
  * 상태를 만든다**(CC-5 교훈: 엔진이 검증 error 상태를 생성하지 않는다). 더 나쁜 건 같은 배치의 형제
@@ -593,6 +612,26 @@ export type ResolveError = {
593
612
  from: string;
594
613
  to: string;
595
614
  };
615
+ }
616
+ /**
617
+ * FK 유래 컬럼의 **파생 형상 필드**를 patch 로 덮으려 했다 — 목록·근거는 `core/fkDerived`
618
+ * (`FK_RELATION_OWNED_FIELDS`)가 소유하고 GUI 잠금과 **같은 목록**이다.
619
+ *
620
+ * ★`attribute-fk-managed`(삭제 차단)의 **필드 축 형제**다. 코드를 가른 이유 = 처방이 다르다(그쪽은
621
+ * *「관계를 지워라」*, 이쪽은 *「그 필드를 patch 에서 빼고 파생원을 고쳐라」*).
622
+ * ★`association` 은 **선택**이다 — 게이트가 `isFkDerivedColumn` 이라 소유 관계를 못 찾는 고아
623
+ * `RELATION_OWN` 도 대상이고(뷰도 그 자리를 잠근다) 그때 지목할 관계가 없다.
624
+ */
625
+ | {
626
+ code: 'attribute-fk-derived-field-locked';
627
+ opIndex: number;
628
+ entity: Handle;
629
+ handle: Handle;
630
+ fields: string[];
631
+ association?: {
632
+ from: string;
633
+ to: string;
634
+ };
596
635
  };
597
636
  export type ResolveNotice = {
598
637
  code: 'inherited-slot-override';
@@ -603,6 +642,22 @@ export type ResolveNotice = {
603
642
  columnIndex: number;
604
643
  /** 그 슬롯에서 **지금 상속 중**인데 이 patch 가 덮어쓰는 필드들. */
605
644
  fields: string[];
645
+ }
646
+ /**
647
+ * FK 유래 컬럼에 **부적합한** 필드에 값을 썼다 — 파생값이 아니라 «그 자리에 의미가 없는» 축이라
648
+ * 거부하지 않고 알린다(목록·근거 = `core/fkDerived.FK_INAPPLICABLE_FIELDS`).
649
+ *
650
+ * ★안내인 근거: 쓰기 자체가 구조 위반은 아니지만 **되돌리는 재주장이 없어 영구 잔존**하는데 뷰가 그
651
+ * 입력을 FK 자리에서 렌더하지 않아 사람이 되짚을 수 없다 ⇒ 「막을 일은 아니지만 모르고 지나갈 일도
652
+ * 아니다」(`inherited-slot-override` 와 같은 판단).
653
+ */
654
+ | {
655
+ code: 'fk-derived-inapplicable-field';
656
+ opIndex: number;
657
+ entity: Handle;
658
+ attribute: Handle;
659
+ /** 호출자가 보낸 그 키(평탄 `unique`·dotted `dbAttrs.0.unique` 등). */
660
+ fields: string[];
606
661
  };
607
662
  export type ResolveResult = {
608
663
  ok: true;
@@ -624,6 +679,12 @@ export interface ResolverOptions {
624
679
  }
625
680
  export declare const ENTITY_SPEC_KEYS: ReadonlySet<string>;
626
681
  export declare const ATTR_SPEC_KEYS: ReadonlySet<string>;
682
+ /**
683
+ * `embeddableOverrides[]` 항목의 허용 키 — **바인딩 축만** 덮는다(컬럼 논리명은 여기 없고 patch 의
684
+ * dotted `dbAttrs.<i>.logicalName` 이 받는다 · `dataType` 도 없다 = 카탈로그가 타입 정본이다).
685
+ * ★`schema.test.ts` 가 이 집합과 `EMBEDDABLE_OVERRIDES.items.properties` 를 대조한다.
686
+ */
687
+ export declare const EMBEDDABLE_OVERRIDE_KEYS: ReadonlySet<string>;
627
688
  export declare const INDEX_SPEC_KEYS: ReadonlySet<string>;
628
689
  export declare const OPERATION_SPEC_KEYS: ReadonlySet<string>;
629
690
  export declare const ASSOC_SPEC_KEYS: ReadonlySet<string>;
@@ -158,6 +158,21 @@ export declare function slotFieldName(attr: Attribute, index: number, model: Log
158
158
  * 77%가 부분 상속**이다(지배 형상 = 논리명«만» 1,273 = 71%). 뭉뚱그리면 「물리명도 상속」으로 읽혀
159
159
  * **무신호를 오신호로 바꾼다**.
160
160
  */
161
+ /**
162
+ * 「ctx 자리가 아닌 곳에 들어온 ctx」 구제 — 값이 «객체»면 ctx 로 본다(`null` 은 ctx 부재 표기라 제외).
163
+ *
164
+ * ★★**왜 필요한가**: 산출 함수들이 ctx 를 **다른 자리**에 둔다 — `validateModel(model, ctx)`·
165
+ * `entityModelToText(logical, ctx)` 는 2번째인데 `entityModelToDdl(logical, dialect, ctx)`·
166
+ * `entityModelToMermaid(logical, dialect, ctx)` 는 3번째다. 한 파일에서 나란히 쓰면 ctx 가 dialect
167
+ * 자리로 들어가 **조용히 사라지고**, 그 degrade 는 «미주입»과 바이트 동일해서 관측으로 구분되지 않는다
168
+ * (실측: 조사 하니스 14파일 23자리가 그렇게 물렸다).
169
+ * ⚠️★**선언 타입은 좁힌 채로 둔다** — 파라미터 타입을 넓히면 TS 호출자가 받던 컴파일 에러가 사라지고
170
+ * 그 에러가 이 함정의 **가장 강한 신호**다. 이 구제는 타입 검사가 없는 호출자(`.mjs` 조사 하니스)에만
171
+ * 닿게 하는 것이 의도다.
172
+ * ★배치 근거: 이 모듈이 **ctx(`ColumnResolveContext`) 개념의 소유자**이고 `ddl`·`mermaid` 둘이 이미
173
+ * 여기에 의존한다 — 한쪽 산출 모듈에 두면 다른 산출이 그쪽을 import 하는 어긋난 방향이 된다.
174
+ */
175
+ export declare function misplacedCtx<T>(slot: unknown): T | undefined;
161
176
  export declare const INHERITABLE_COLUMN_FIELDS: readonly ["physicalName", "dataType", "length", "scale", "logicalName"];
162
177
  export type InheritableColumnField = (typeof INHERITABLE_COLUMN_FIELDS)[number];
163
178
  /**
@@ -6,5 +6,20 @@ export interface DdlContext {
6
6
  }
7
7
  /** 표시 모드 → 기본 DDL 방언. 현재는 PG 단일. */
8
8
  export declare function defaultSqlDialect(): SqlDialect;
9
- /** 논리 모델을 지정 방언의 SQL DDL로 직렬화. */
10
- export declare function entityModelToDdl(logical: LogicalModel, _dialect?: SqlDialect, ctx?: DdlContext): string;
9
+ /**
10
+ * 논리 모델을 지정 방언의 SQL DDL로 직렬화.
11
+ *
12
+ * ⚠️★★**2번째 자리는 «함정»이다** — `SqlDialect` 은 값이 하나(`'postgres'`)이고 본문이 그것을 **읽지도
13
+ * 않는데**, 그 죽은 파라미터가 `ctx` 앞을 차지한다. 형제 함수들이 자리를 달리 두므로
14
+ * (`validateModel(model, ctx)`·`entityModelToText(logical, ctx)` = **2번째**) 한 파일에서 나란히 쓰면
15
+ * `entityModelToDdl(l, {embeddableCatalog})` 처럼 **ctx 가 dialect 자리로 들어가 조용히 사라진다**.
16
+ * 실측 파급: 조사 하니스 **14파일 23자리**가 그렇게 물려 EMBED_PREDEF 축을 **미주입과 바이트 동일**하게
17
+ * 재고 있었고(「복구 0/392」는 하니스 자신이 만든 관측) 그 자리는 타입 검사가 없는 `.mjs` 였다.
18
+ *
19
+ * ⇒ ★**런타임 구제만 한다 — 선언 타입은 좁힌 채로 둔다.** 2번째가 «객체»면 그것을 ctx 로 읽는다.
20
+ * 시그니처를 `(logical, ctx)` 로 정정하는 쪽이 근본이지만 이 함수는 **공개 표면**(`src/index.ts`)이라
21
+ * breaking 이고(다음 메이저 소관), 반대로 파라미터 타입을 `SqlDialect | DdlContext` 로 넓히면 **TS
22
+ * 호출자가 받던 컴파일 에러가 사라진다** — 그 에러가 이 함정의 가장 강한 신호다. 그래서 타입은 그대로,
23
+ * 구제는 «타입 검사가 없는 호출자»(조사 하니스)에만 닿게 한다.
24
+ */
25
+ export declare function entityModelToDdl(logical: LogicalModel, dialect?: SqlDialect, ctx?: DdlContext): string;
@@ -115,3 +115,48 @@ export declare function isEmbeddedPkAttr(attr: Attribute): boolean;
115
115
  * 멤버십 판정은 **`isPkMemberAttr` 단일 출처**다(위 주석의 「세 곳 복제」 사고 이후).
116
116
  */
117
117
  export declare function parentIdColumns(parent: Entity | undefined): DbColumn[];
118
+ /**
119
+ * FK 유래 컬럼에서 **관계가 소유하는** patch 필드 — 값의 파생원이 모델에 실재한다(부모 PK 컬럼 형상 +
120
+ * 부모 end 다중성 + 관계 `identifying`). 뷰는 이 자리를 disabled 로 잠그고(`useAttributeEditing.fkDerived`
121
+ * 게이트 · 프로브 `verify-fk-derived-locking.mjs` 가 11 단언으로 그 집합을 성문화), AI 경로는 **구조 거부**
122
+ * 한다 — 두 경로가 **같은 목록**을 봐야 *「GUI 로는 못 하는데 AI 로는 조용히 된다」* 가 안 난다.
123
+ *
124
+ * ★★**`type`·`attrType` 은 여기 없다** — 그 축은 `core/javaTypes.typeOwner`(=`derived`)가 소유하고 AI
125
+ * 경로도 그것으로 이미 거부한다(`attribute-type-conversion-unsupported` reason=`derived`). 두 번 적으면
126
+ * 판정이 갈린다(이 리포가 반복해 싸운 미러 드리프트).
127
+ * ★**`groupCode` 도 없다** — FK 의 `type` 이 `GroupCodeEnum` 이 될 수 없으므로 `isGroupCodeCouplingBroken`
128
+ * 이 그 조합을 **이미** 거부한다(`groupcode-type-mismatch`).
129
+ * ⚠️`notNull` 은 실해가 0 이다(`deriveFkNotNull` 이 **매 로드** 재주장하고 호스트 `/text` 도 그 로드를
130
+ * 지난다) — 그래도 목록에 두는 이유는 **조용한 no-op 이 에러보다 나쁘기** 때문이다: 쓰면 저장되고 다음
131
+ * 로드에 사라져 「썼는데 없다」가 되는데 그 시점이 예측되지 않는다.
132
+ * ⚠️★**비우기(`null`)도 함께 막는다** — 뷰는 이 자리를 «설정도 해제도» 못 하게 잠그므로 대칭이 그쪽이고,
133
+ * 정렬 수단은 파생원(관계 인스펙터의 다중성·식별관계)과 reconcile 이다.
134
+ */
135
+ export declare const FK_RELATION_OWNED_FIELDS: {
136
+ /** 속성 층 — 파생원이 **관계**다(다중성·identifying). */
137
+ readonly attr: readonly ["identifier", "notNull"];
138
+ /** 컬럼 층 — 파생원이 **부모 PK 컬럼**이다(`propagation.diffSyncedFields` 가 재주장하는 그 셋). */
139
+ readonly column: readonly ["dataType", "length", "scale"];
140
+ };
141
+ /**
142
+ * FK 유래 컬럼에 **부적합한** 필드 — 파생값이 아니라 «그 자리에 의미가 없는» 축이라 위와 **근거가 다르다**
143
+ * (레거시 FK 폼이 이 입력을 렌더하지 않는다 — `EntityColumnsSection` 의 `v-if="!fkDerived(a)"` 주석).
144
+ *
145
+ * ⇒ ★**처방도 다르다: 거부가 아니라 «안내»**(`fk-derived-inapplicable-field`). 파생값 축과 달리 재주장하는
146
+ * 자리가 **없어서** 값이 **영구 잔존**하는데, 뷰가 그 입력을 아예 안 내므로 사람이 되짚을 수 없다 —
147
+ * 즉 조용히 남는 쪽이 문제이고 쓰기 자체가 구조 위반은 아니다.
148
+ * ⚠️**비우기는 안내하지 않는다** — 부적합 값을 «지우는» 것은 정당한 정리다(방향이 반대).
149
+ * ⚠️★**`sequenceName`·`multiValueSeparator` 는 여기 없다** — 이 목록의 근거는 *「FK 폼이 안 내는데 NORMAL
150
+ * 폼은 낸다」* 는 대조인데 그 둘은 **뷰가 어디에도 없다** ⇒ FK 특정 근거를 세울 수 없다(무★ 규율 —
151
+ * 근거 없는 항목을 목록에 넣으면 그 자체가 발명이다). `naturalIdMutable` 은 `naturalId` **종속** 플래그라
152
+ * FK 축이 아니라 의존 축이다.
153
+ */
154
+ export declare const FK_INAPPLICABLE_FIELDS: {
155
+ readonly attr: readonly ["transient", "naturalId", "defaultValue", "personalInfoAttributeType"];
156
+ /**
157
+ * 컬럼 층. ⚠️`notNull` 이 **양쪽 목록에 다 있는 것이 아니다** — 속성 층 `notNull` 은 파생값(위)이고,
158
+ * 여기의 것은 **컬럼 3-상태**(임베드 슬롯 축)라 FK 자리에서는 읽히지 않는다(FK 의 NOT NULL 은 속성 층이
159
+ * 정한다) ⇒ 층이 다르고 근거가 다르다.
160
+ */
161
+ readonly column: readonly ["unique", "autoIncrement", "multiValue", "notNull"];
162
+ };