@g1cloud/entity-modeler-next 5.0.0-beta.2 → 5.0.0-beta.24

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/dist/i18n/ko.d.ts CHANGED
@@ -47,6 +47,10 @@ export declare const ko: {
47
47
  readonly 'em.panel.expandAll': "모두 펼치기";
48
48
  readonly 'em.panel.lockedBanner': "편집 잠김 — 이동·수정·삭제 차단";
49
49
  readonly 'em.panel.openNamed': "{name} 열기";
50
+ readonly 'em.notice.readOnly': "조회 모드에서는 편집할 수 없습니다";
51
+ readonly 'em.notice.entityLocked': "잠긴 엔티티입니다 — 잠금 해제 후 편집하세요";
52
+ readonly 'em.notice.groupLocked': "잠긴 그룹입니다 — 잠금 해제 후 편집하세요";
53
+ readonly 'em.notice.assocLocked': "잠긴 엔티티에 연결된 관계입니다 — 잠금 해제 후 편집하세요";
50
54
  readonly 'em.validation.title': "검증";
51
55
  readonly 'em.validation.noIssues': "검증 이슈가 없습니다.";
52
56
  readonly 'em.validation.noVisibleIssues': "표시할 이슈가 없습니다 (필터 적용 중).";
@@ -120,6 +124,14 @@ export declare const ko: {
120
124
  readonly 'em.common.inherit': "기본(따름)";
121
125
  readonly 'em.common.noneParen': "(없음)";
122
126
  readonly 'em.swatch.none': "없음";
127
+ readonly 'em.swatch.red': "빨강";
128
+ readonly 'em.swatch.amber': "주황";
129
+ readonly 'em.swatch.green': "초록";
130
+ readonly 'em.swatch.teal': "청록";
131
+ readonly 'em.swatch.blue': "파랑";
132
+ readonly 'em.swatch.indigo': "남색";
133
+ readonly 'em.swatch.violet': "보라";
134
+ readonly 'em.swatch.pink': "분홍";
123
135
  readonly 'em.inspector.ctxEntityAttrs': "엔티티 · {name} › 속성 · {n}개";
124
136
  readonly 'em.inspector.ctxEntityDivider': "엔티티 · {name} › 구분선";
125
137
  readonly 'em.inspector.ctxEntityAttr': "엔티티 · {name} › 속성 · {attr}";
@@ -135,6 +147,8 @@ export declare const ko: {
135
147
  readonly 'em.assoc.navFieldName': "연관 필드명(nav)";
136
148
  readonly 'em.assoc.cascadeAllNote': "ALL이 개별 cascade를 모두 포함합니다 (CHK-JPA-5).";
137
149
  readonly 'em.assoc.orphanRemovalNote': "반대편이 컬렉션(@ManyToOne/@ManyToMany)이라 orphanRemoval이 무효입니다 (CHK-JPA-14).";
150
+ readonly 'em.assoc.navRequiredNote': "이 방향에 nav 속성이 없어(navigable 꺼짐) cascade·fetch가 적용되지 않습니다.";
151
+ readonly 'em.assoc.ownerNavFixed': "JPA 소유측 참조(@ManyToOne)는 관계 존재와 동치라 항상 켜집니다 — 참조 없는 FK는 관계 대신 일반 컬럼으로 모델링하세요.";
138
152
  readonly 'em.assoc.orderByPlaceholder': "예: name ASC";
139
153
  readonly 'em.assoc.jpaDetails': "JPA 상세";
140
154
  readonly 'em.embed.legend': "임베드";
@@ -169,6 +183,10 @@ export declare const ko: {
169
183
  readonly 'em.attr.nameless': "(이름 없음)";
170
184
  readonly 'em.attr.selectHint': "위 목록에서 속성을 선택하면 편집 폼이 표시됩니다.";
171
185
  readonly 'em.attr.inverseNavHint': "역방향 연관관계 필드 — 물리 컬럼이 없습니다(대상 엔티티 참조).";
186
+ readonly 'em.attr.fkDerivedNote': "외래키(FK)에서 파생된 컬럼입니다 — 형상은 부모 PK를 따르며, 변경은 관계선·식별관계에서 하세요.";
187
+ readonly 'em.attr.scaleTypeHint': "소수부(scale)는 NUMERIC·DECIMAL 타입에만 적용됩니다.";
188
+ readonly 'em.attr.embedFixedHint': "임베더블 정의에서 고정된 값입니다.";
189
+ readonly 'em.attr.embedSharedHint': "다른 컬럼과 공유하는 통화 컬럼입니다 — 대상에서 파생(읽기 전용).";
172
190
  readonly 'em.attr.namePlaceholder': "이름";
173
191
  readonly 'em.attr.typePlaceholder': "타입";
174
192
  readonly 'em.attr.customTypePlaceholder': "커스텀 타입명";
@@ -241,8 +259,13 @@ export declare const ko: {
241
259
  readonly 'em.cmd.groupTag': "그룹";
242
260
  readonly 'em.canvas.emptyTitle': "빈 다이어그램입니다";
243
261
  readonly 'em.canvas.emptyHint': "캔버스를 <strong>우클릭</strong>하거나 좌하단 <strong>+</strong> 버튼으로 첫 엔티티를 추가하세요.";
262
+ readonly 'em.canvas.emptyConnectHint': "엔티티를 두 개 이상 만들면, 엔티티 가장자리에서 <strong>드래그</strong>해 관계를 연결할 수 있어요.";
244
263
  readonly 'em.canvas.emptyShortcutHint': "단축키 도움말은 <kbd>?</kbd> 키";
245
264
  readonly 'em.canvas.emptyReadonly': "표시할 엔티티가 없습니다";
265
+ readonly 'em.canvas.exportFailed': "내보내기에 실패했습니다";
266
+ readonly 'em.conflict.lockedTitle': "편집이 잠겼습니다";
267
+ readonly 'em.conflict.missingDetail': "변경 사항을 저장하지 못했습니다(서버 또는 네트워크 오류). 최신 내용을 다시 불러오세요.";
268
+ readonly 'em.conflict.changedDetail': "다른 곳에서 변경되어 편집이 잠겼습니다. 최신 내용을 다시 불러오세요.";
246
269
  readonly 'em.ctx.addEntity': "엔티티 추가";
247
270
  readonly 'em.ctx.addNote': "노트 추가";
248
271
  readonly 'em.ctx.addGroup': "그룹 추가";
@@ -277,6 +300,7 @@ export declare const ko: {
277
300
  readonly 'em.node.required': "필수 (NOT NULL)";
278
301
  readonly 'em.node.logicalMissing': "(논리명)";
279
302
  readonly 'em.node.editLock': "편집 잠금";
303
+ readonly 'em.node.connectHint': "드래그해 다른 엔티티와 관계 연결";
280
304
  readonly 'em.node.opsSummaryTitle': "오퍼레이션 {n}개 — 클래스 표시 모드에서 펼쳐 보입니다";
281
305
  readonly 'em.node.opsSummary': "오퍼레이션 {n}개";
282
306
  readonly 'em.node.addAttr': "+ 속성";
@@ -318,6 +342,18 @@ export declare const ko: {
318
342
  readonly 'em.history.doRestore': "복원";
319
343
  readonly 'em.history.cancel': "취소";
320
344
  readonly 'em.history.restoreToHere': "이 시점으로 복원";
345
+ readonly 'em.history.diff.compare': "현재와 비교";
346
+ readonly 'em.history.diff.current': "현재";
347
+ readonly 'em.history.diff.exit': "비교 해제";
348
+ readonly 'em.history.diff.count': "누적 변경 {n}건";
349
+ readonly 'em.history.diff.empty': "이 구간의 누적 변경이 없습니다.";
350
+ readonly 'em.history.diff.restorePreview': "되돌아갈 변경 {n}건";
351
+ readonly 'em.history.diff.restorePreviewNone': "되돌아갈 변경이 없습니다.";
352
+ readonly 'em.history.loadMore': "이전 기록 더 보기 ({n})";
353
+ readonly 'em.history.periodLabel': "기간";
354
+ readonly 'em.history.periodFrom': "시작일";
355
+ readonly 'em.history.periodTo': "종료일";
356
+ readonly 'em.history.periodReset': "기간 해제";
321
357
  readonly 'em.check.catName': "이름";
322
358
  readonly 'em.check.catJpa': "JPA";
323
359
  readonly 'em.check.catType': "타입";
@@ -331,6 +367,7 @@ export declare const ko: {
331
367
  readonly 'em.check.name6Column': "컬럼 물리명이 SQL 예약어입니다: \"{name}\"";
332
368
  readonly 'em.check.name6Table': "테이블 물리명이 SQL 예약어입니다: \"{name}\"";
333
369
  readonly 'em.check.name6Index': "인덱스 이름이 SQL 예약어입니다: \"{name}\"";
370
+ readonly 'em.check.name7': "관계/임베드 속성({attrType})의 이름이 비어 있습니다 — 이름이 곧 JPA 필드명이라 코드 생성 시 이 관계가 통째로 누락됩니다. 속성명을 채우세요";
334
371
  readonly 'em.check.jpa1': "JPA 엔티티에 식별자(PK) 속성이 없습니다";
335
372
  readonly 'em.check.jpa2': "임베더블 타입은 식별자 속성을 가질 수 없습니다: \"{name}\"";
336
373
  readonly 'em.check.jpa4': "식별 관계 사이클입니다 (PK 무한 의존): {path}";
@@ -348,6 +385,8 @@ export declare const ko: {
348
385
  readonly 'em.check.jpa15': "식별자(@Id) 속성은 자연키(@NaturalId)일 수 없습니다 — 자연키는 PK와 별개의 비즈니스 키입니다: \"{name}\"";
349
386
  readonly 'em.check.jpa16': "자연키(@NaturalId) 속성은 transient(@Transient)일 수 없습니다: \"{name}\"";
350
387
  readonly 'em.check.jpa17': "자연키(@NaturalId) 속성은 not null이 권장됩니다(비즈니스 키는 non-null이 원칙): \"{name}\"";
388
+ readonly 'em.check.jpa18': "cascade가 관계 양쪽(부모·자식)에 모두 설정되어 양방향 전파됩니다 — 의도치 않은 연쇄 저장/삭제·전파 사이클 위험. 보통 cascade는 한쪽에만 둡니다";
389
+ readonly 'em.check.jpa19': "부모에 컬렉션/참조 필드가 있으나 자식({child})에 대응 관계 속성이 없어 JPA 매핑(mappedBy)을 만들 수 없습니다 — 코드젠이 이 관계를 방출하지 못합니다. 자식에 FK 속성을 만들거나 관계를 단방향으로 정리하세요";
351
390
  readonly 'em.check.type1': "타겟 DB가 지원하지 않는 컬럼 타입입니다: \"{dataType}\"";
352
391
  readonly 'em.check.type2': "{dataType} 타입에 length가 지정되지 않았습니다";
353
392
  readonly 'em.check.type3': "공유 대상 컬럼의 타입({targetType})이 {metaName} 정의({metaType})와 다릅니다";
package/dist/index.d.ts CHANGED
@@ -13,13 +13,16 @@ export * from './core/validation';
13
13
  export * from './core/quickFix';
14
14
  export * from './core/sharedColumn';
15
15
  export { JAVA_TYPES, SELECTABLE_JAVA_TYPES, javaTypeLabel, CUSTOM_TYPE_VALUE, GROUP_CODE_ENUM_VALUE, DEFAULT_JAVA_TYPE, type JavaTypeDef, } from './core/javaTypes';
16
- export { scaffoldEntityJava, type ScaffoldOptions, type ScaffoldedEntity, } from './core/scaffoldJava';
16
+ export { scaffoldEntityJava, isGeneratable, type ScaffoldOptions, type ScaffoldedEntity, } from './core/scaffoldJava';
17
17
  export { migrateLegacyMoney } from './core/migrateLegacyMoney';
18
+ export { multiplicityLabel } from './core/associationNav';
19
+ export { stereotypeLabel } from './core/stereotype';
18
20
  export { mergeDiagram, type MergeDiagramSource, type MergeDiagramOptions, type MergeDiagramResult, } from './core/mergeDiagram';
19
21
  export { synthesizeRestoreOps, deepEqual as restoreDeepEqual, type DiagramSnapshotState } from './core/synthesizeRestoreOps';
20
22
  export { projectFieldAudit, type FieldAuditRecord, type FieldAuditTarget, type FieldAuditEntry } from './core/projectFieldAudit';
21
23
  export { projectEntityAudit, type EntityAuditEntry, type EntityAuditSubject, type EntityAuditSubjectKind } from './core/projectEntityAudit';
22
24
  export { projectActionLog, type ActionGroup, type SubjectAction, type ActionSubject, type ActionSubjectKind, type ActionFieldChange } from './core/projectActionLog';
25
+ export { projectSeqDiff, buildDiffMarks, type SeqDiff, type SeqDiffEntry, type DiffMark } from './core/projectSeqDiff';
23
26
  export { projectInheritedColumns, makeInheritedColumnRef, isInheritedColumnRef, parseInheritedColumnRef, INHERITED_REF_PREFIX, type InheritedColumn, } from './core/inheritedColumns';
24
27
  export { newId } from './core/id';
25
28
  export * from './command/types';
@@ -32,6 +35,7 @@ export * from './agent/resolver';
32
35
  export * from './agent/schema';
33
36
  export * from './agent/buildAgentBatch';
34
37
  export * from './adapter/diagramAdapter';
38
+ export { planHealBackfillOps, type HealBackfillPlan } from './adapter/healBackfill';
35
39
  export type * from './adapter/persisted';
36
40
  export { default as EntityNode } from './view/EntityNode.vue';
37
41
  export { default as GroupNode } from './view/GroupNode.vue';
@@ -1,11 +1,15 @@
1
+ import { DiffMark } from '../core/projectSeqDiff';
1
2
  import { EditorController } from '../editor/controller';
3
+ import { ModelId } from '../core/types';
2
4
  type __VLS_Props = {
3
5
  controller: EditorController;
6
+ diffMarks?: Map<ModelId, DiffMark> | null;
4
7
  };
5
8
  declare function exportSvg(): Promise<void>;
6
9
  declare function exportPng(): Promise<void>;
7
10
  declare const _default: import('vue').DefineComponent<__VLS_Props, {
8
11
  exportSvg: typeof exportSvg;
9
12
  exportPng: typeof exportPng;
13
+ fitView: import('@vue-flow/core').FitView;
10
14
  }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
11
15
  export default _default;
@@ -1,3 +1,4 @@
1
+ import { DiffMark } from '../core/projectSeqDiff';
1
2
  import { EditorController } from '../editor/controller';
2
3
  type __VLS_Props = {
3
4
  controller: EditorController;
@@ -5,7 +6,9 @@ type __VLS_Props = {
5
6
  };
6
7
  declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
7
8
  close: () => any;
9
+ diffChange: (marks: Map<string, DiffMark> | null) => any;
8
10
  }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
9
11
  onClose?: (() => any) | undefined;
12
+ onDiffChange?: ((marks: Map<string, DiffMark> | null) => any) | undefined;
10
13
  }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
11
14
  export default _default;
@@ -0,0 +1,14 @@
1
+ import { InjectionKey, Ref } from 'vue';
2
+ import { ModelId } from '../core/types';
3
+ import { DiffMark } from '../core/projectSeqDiff';
4
+ /**
5
+ * 이력 diff 비교 모드의 캔버스 오버레이 주입 계약(RELATION_HIGHLIGHT 동형 — 일시적 시각 강조,
6
+ * 모델 무관). 셸(EntityModeler/DevApp)이 HistoryPanel의 비교 diff 마크를 소유하고 DiagramCanvas가
7
+ * prop으로 받아 provide, EntityNode가 구독한다(D4-(a) 뷰 소유 — core/controller 무변경).
8
+ *
9
+ * null = 비교 모드 아님(오버레이 없음). removed 대상은 캔버스에 노드가 없어 맵에 없다(D3 패널 전용).
10
+ */
11
+ export interface DiffOverlay {
12
+ marks: Ref<Map<ModelId, DiffMark> | null | undefined>;
13
+ }
14
+ export declare const DIFF_OVERLAY: InjectionKey<DiffOverlay>;
@@ -0,0 +1,15 @@
1
+ import { InjectionKey } from 'vue';
2
+ /**
3
+ * 노드 내부 handle 재측정 요청 수집기 (VE-1 ①) — 캔버스가 provide, EntityNode가 onUpdated마다
4
+ * 자기 id를 mark(무비용 후보 등록). 캔버스는 rAF 배치 flush에서 후보의 기하 시그니처(노드 높이 +
5
+ * 행별 y)를 비교해 **실제로 변한 노드만** `updateNodeInternals(ids)`로 재측정한다.
6
+ *
7
+ * 왜 시그니처 판정이 필수인가: Vue Flow의 updateNodeInternals는 forceUpdate로 handleBounds를
8
+ * 무조건 새 객체로 써 그 노드를 다시 재렌더시킨다 — 재렌더를 무조건 mark하면 측정→재렌더→측정
9
+ * 무한 루프. 시그니처가 무변화면 측정을 생략해 루프가 한 사이클 만에 종료된다. 부수 효과로
10
+ * 텍스트-only 변경·hover 강조 재렌더도 재측정에서 자연 제외된다.
11
+ */
12
+ export interface NodeInternalsCollector {
13
+ mark: (nodeId: string) => void;
14
+ }
15
+ export declare const NODE_INTERNALS: InjectionKey<NodeInternalsCollector>;
@@ -1,12 +1,14 @@
1
1
  import { OpConflict } from '../command/op';
2
+ import { MessageKey } from '../i18n';
2
3
  export interface OpConflictNotice {
3
- /** 배너 제목 — 상태 자체(무엇이 일어났는지). */
4
- title: string;
5
- /** 배너 본문 — 원인 + 복구 방향(다시 불러오기). */
6
- detail: string;
4
+ /** 배너 제목 — 상태 자체(무엇이 일어났는지). 뷰가 t()로 렌더. */
5
+ titleKey: MessageKey;
6
+ /** 배너 본문 — 원인 + 복구 방향(다시 불러오기). 뷰가 t()로 렌더. */
7
+ detailKey: MessageKey;
7
8
  }
8
9
  /**
9
- * 충돌 종류 → 사용자 문구. `missing`은 동시편집이 아니라 전송 실패(혼자 편집 중에도 발생)라 원인을
10
- * 구분한다(호스트 배선 경로와 동일한 kind 오진 방지). null → null(배너 미노출).
10
+ * 충돌 종류 → 사용자 문구 **키**(문구는 i18n 카탈로그 소유 검증 P3 code+params→뷰 지역화 패턴 동형).
11
+ * `missing`은 동시편집이 아니라 전송 실패(혼자 편집 중에도 발생) 원인을 구분한다
12
+ * (호스트 배선 경로와 동일한 kind 오진 방지). null → null(배너 미노출).
11
13
  */
12
14
  export declare function opConflictNotice(conflict: OpConflict | null | undefined): OpConflictNotice | null;
@@ -1,3 +1,4 @@
1
+ import { MessageKey } from '../i18n';
1
2
  import { Style } from '../core/types';
2
3
  export type SwatchToken = 'red' | 'amber' | 'green' | 'teal' | 'blue' | 'indigo' | 'violet' | 'pink';
3
4
  /** 토큰의 컨텍스트별 렌더값 (CSS 변수 참조 — 테마는 [data-theme]로 스왑) */
@@ -31,7 +32,7 @@ export declare function resolveSwatch(token: SwatchToken | null): SwatchRender |
31
32
  * @param soft 그룹처럼 반투명 칠이 필요하면 true.
32
33
  */
33
34
  export declare function swatchMinimapFill(token: SwatchToken | null, soft?: boolean): string | null;
34
- /** 피커 라벨 */
35
- export declare function swatchLabel(token: SwatchToken): string;
35
+ /** 피커 라벨 키 — 소비처가 `t(swatchLabelKey(token))`으로 로케일 렌더 */
36
+ export declare function swatchLabelKey(token: SwatchToken): MessageKey;
36
37
  /** 피커에 칠할 대표색 (바 색 — 피커도 [data-theme]에 따라 전환) */
37
38
  export declare function swatchSwatchColor(token: SwatchToken): string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@g1cloud/entity-modeler-next",
3
3
  "private": false,
4
- "version": "5.0.0-beta.2",
4
+ "version": "5.0.0-beta.24",
5
5
  "description": "Vue 3 visual entity-modeling / class-diagram editor",
6
6
  "type": "module",
7
7
  "files": [
@@ -31,8 +31,7 @@
31
31
  "@vue-flow/background": "^1.3.2",
32
32
  "@vue-flow/controls": "^1.1.2",
33
33
  "@vue-flow/core": "^1.42.1",
34
- "@vue-flow/minimap": "^1.5.2",
35
- "pinia": "^2.2.0"
34
+ "@vue-flow/minimap": "^1.5.2"
36
35
  },
37
36
  "devDependencies": {
38
37
  "@g1cloud/open-bluesea-core": "1.0.0-alpha.9",
@@ -45,7 +44,7 @@
45
44
  "typescript": "^5.6.0",
46
45
  "vite": "^6.0.0",
47
46
  "vite-plugin-dts": "^5.0.3",
48
- "vitest": "^2.1.0",
47
+ "vitest": "^3.0.0",
49
48
  "vue": "^3.5.0",
50
49
  "vue-tsc": "^2.1.0"
51
50
  },
@@ -55,7 +54,8 @@
55
54
  "preview": "vite preview",
56
55
  "test": "vitest run",
57
56
  "test:watch": "vitest",
58
- "verify:m0": "node scripts/verify-m0.mjs",
59
- "typecheck": "vue-tsc --noEmit"
57
+ "verify": "node scripts/verify-all.mjs",
58
+ "typecheck": "vue-tsc --noEmit",
59
+ "check": "pnpm run test && pnpm run build"
60
60
  }
61
61
  }