@g1cloud/entity-modeler-next 5.0.0-beta.47 → 5.0.0-beta.49
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 +6 -0
- package/dist/editor/association.d.ts +18 -0
- package/dist/editor/attribute.d.ts +25 -0
- package/dist/editor/commandPlans.d.ts +22 -2
- package/dist/editor/entity.d.ts +19 -0
- package/dist/editor/group.d.ts +22 -0
- package/dist/editor/note.d.ts +11 -0
- package/dist/editor/selection.d.ts +1 -6
- package/dist/entity-modeler-next.css +1 -1
- package/dist/entity-modeler.js +12625 -12259
- package/dist/entity-modeler.umd.cjs +24 -24
- package/dist/i18n/ko.d.ts +7 -0
- package/dist/view/DiagramCanvas.vue.d.ts +5 -0
- package/dist/view/columnResolution.d.ts +85 -0
- package/dist/view/embedSlotCollapse.d.ts +36 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -48,8 +48,14 @@ pnpm test:coverage # Vitest + v8 coverage report (no threshold — report only)
|
|
|
48
48
|
pnpm typecheck # vue-tsc --noEmit
|
|
49
49
|
pnpm build # library build (dist/)
|
|
50
50
|
pnpm verify # headless GUI probe suite (scripts/verify-*.mjs) — boots the dev harness once, runs all probes
|
|
51
|
+
pnpm verify:floor # raise the per-probe assertion-count floor to current (never lowers)
|
|
51
52
|
pnpm check # CI gate: test && build
|
|
52
53
|
```
|
|
53
54
|
|
|
54
55
|
`check` is the entry point CI calls; `verify` runs the browser probes and is kept separate because it needs a
|
|
55
56
|
dev server and takes ~100s.
|
|
57
|
+
|
|
58
|
+
`verify` also enforces a per-probe **assertion-count floor** (`scripts/probe-assertion-floor.json`): a probe whose
|
|
59
|
+
executed-assertion total drops below its floor fails even if every remaining assertion passes — deleting an `ok()`
|
|
60
|
+
would otherwise shrink the denominator too and pass as `0/0`. Adding assertions needs no bookkeeping; only a
|
|
61
|
+
deliberate reduction requires editing the JSON by hand, and that diff is the review signal.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { Command, EditorState } from '../command/types';
|
|
3
|
+
import { EditorController } from './controller';
|
|
4
|
+
import { ModelId } from '../core/types';
|
|
5
|
+
/** 이 축이 팩토리 클로저에서 쓰는 것 전부. 늘어나면 여기 선언이 먼저 늘어난다(= 의존 인벤토리). */
|
|
6
|
+
export interface AssociationContext {
|
|
7
|
+
/** 편집 대상 reactive 상태(속성만 교체되므로 참조 안정). */
|
|
8
|
+
state: EditorState;
|
|
9
|
+
/** 조회 모드 판정 — add류가 `null`을 돌려주려면 run()의 no-op 백스톱보다 앞에서 봐야 한다. */
|
|
10
|
+
editable: Ref<boolean>;
|
|
11
|
+
/** 모델 변경의 단일 실행점(조회 모드 no-op + 안내). */
|
|
12
|
+
run: (c: Command) => void;
|
|
13
|
+
/** 잠금 게이트(엔티티) — 관계 *생성*은 관계가 아직 없어 양 끝을 각각 본다. */
|
|
14
|
+
gateEntityLocked: (id: ModelId) => boolean;
|
|
15
|
+
/** 잠금 게이트(관계) — 양끝 중 하나라도 잠기면 차단(그 의미론의 단일 출처). */
|
|
16
|
+
gateAssocLocked: (assocId: ModelId) => boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function createAssociationApi(ctx: AssociationContext): Pick<EditorController, 'addAssociation' | 'addEmbedAssociation' | 'setEmbedCardinality' | 'removeAssociation' | 'setAssociationIdentifying' | 'updateAssociationEnd'>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { Command, EditorState } from '../command/types';
|
|
3
|
+
import { Translator } from '../i18n';
|
|
4
|
+
import { EditorController, Selection } from './controller';
|
|
5
|
+
import { EmbeddableCatalog, ModelId } from '../core/types';
|
|
6
|
+
/** 이 축이 팩토리 클로저에서 쓰는 것 전부. 늘어나면 여기 선언이 먼저 늘어난다(= 의존 인벤토리). */
|
|
7
|
+
export interface AttributeContext {
|
|
8
|
+
/** 편집 대상 reactive 상태(속성만 교체되므로 참조 안정). */
|
|
9
|
+
state: EditorState;
|
|
10
|
+
/** 조회 모드 판정 — add류가 `null`을 돌려주려면 run()의 no-op 백스톱보다 앞에서 봐야 한다. */
|
|
11
|
+
editable: Ref<boolean>;
|
|
12
|
+
/** 모델 변경의 단일 실행점(조회 모드 no-op + 안내). */
|
|
13
|
+
run: (c: Command) => void;
|
|
14
|
+
/** 잠금 게이트 — 차단 시 true + 안내 emit. 속성 편집은 소속 엔티티 잠금을 따른다. */
|
|
15
|
+
gateEntityLocked: (entityId: ModelId) => boolean;
|
|
16
|
+
/** 호스트 주입 임베더블 카탈로그(`addPredefinedEmbed`의 슬롯 골격 소스). */
|
|
17
|
+
embeddableCatalog: Ref<EmbeddableCatalog>;
|
|
18
|
+
/** UI 크롬 번역기 — FK 직접 삭제 차단 안내 문구용. */
|
|
19
|
+
t: Translator;
|
|
20
|
+
/** 차단 안내(텍스트별 단기 dedup) — 무음 차단을 막는 백스톱. */
|
|
21
|
+
emitGateNotice: (text: string) => void;
|
|
22
|
+
/** 삭제된 행을 선택이 가리키지 않도록 해제하는 쓰기(`removeAttributes`). */
|
|
23
|
+
selection: Ref<Selection>;
|
|
24
|
+
}
|
|
25
|
+
export declare function createAttributeApi(ctx: AttributeContext): Pick<EditorController, 'addPredefinedEmbed' | 'addAttribute' | 'addDivider' | 'updateAttribute' | 'setAttributeGroupCode' | 'setEmbedColumns' | 'removeAttribute' | 'removeAttributes' | 'setAttributeSwatch' | 'setAttributeSwatches' | 'reorderAttributes'>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Command } from '../command/types';
|
|
1
|
+
import { Command, EditorState } from '../command/types';
|
|
2
2
|
import { ReconcilePlan } from '../core/propagation';
|
|
3
|
-
import { Attribute, DbColumn, Entity, LogicalModel, ModelId } from '../core/types';
|
|
3
|
+
import { Attribute, DbColumn, Entity, LogicalModel, ModelId, Point } from '../core/types';
|
|
4
4
|
/**
|
|
5
5
|
* 식별자 전파 reconcile 계획을 자식 엔터티 대상 서브명령 배열로 변환.
|
|
6
6
|
* 1차 변경(관계 생성/삭제 등)과 함께 composite로 묶으면 전파 FK 동기화가 하나의 undo/redo
|
|
@@ -65,3 +65,23 @@ export declare function flattenEmbeddableColumns(embeddable: Entity): DbColumn[]
|
|
|
65
65
|
*/
|
|
66
66
|
export declare function leavingEmbeddableCommands(logical: LogicalModel, id: ModelId): Command[];
|
|
67
67
|
export declare function enteringEmbeddableCommands(logical: LogicalModel, id: ModelId): Command[];
|
|
68
|
+
/**
|
|
69
|
+
* 그룹 이동 명령 집합 — 그룹 박스 + 멤버 절대좌표 + 내부 관계 waypoint를 같은 delta로.
|
|
70
|
+
* 드래그(`./group` dragGroup)·키보드(`./selection` nudgeNodes) 양쪽에서 재사용; 호출부가
|
|
71
|
+
* composite로 감싸 한 명령으로 실행한다.
|
|
72
|
+
*
|
|
73
|
+
* ★**이 파일에서 유일하게 `LogicalModel`이 아니라 `EditorState`를 받는다**(위 헤더 계약의 예외).
|
|
74
|
+
* 그룹 이동은 본질적으로 레이아웃 연산이라 `groupLayouts`·`associationLayouts`·`notes`를 읽어야
|
|
75
|
+
* 하고, 그러면서 멤버십 판정(`logical.groups`)·내부 관계 판정(`logical.associations`)도 필요해
|
|
76
|
+
* 양 뎁스를 함께 본다. 순수성(같은 입력 → 같은 `Command[]`)은 그대로다.
|
|
77
|
+
* ★**여기로 내려온 경위**(VE-6 결정 ②): 팩토리 클로저 안에 있으면서 `./selection`에 주입되고
|
|
78
|
+
* `dragGroup`(컨트롤러)도 쓰던 함수다. S8이 그룹 축을 분리하면서 **소비자 둘 다 외부 모듈**이
|
|
79
|
+
* 되어, 팩토리가 자기는 쓰지 않는 헬퍼를 들고 두 모듈에 배관만 하는 형태가 됐다 ⇒ 중립 위치인
|
|
80
|
+
* 여기로 내리고 양쪽이 직접 import 한다(`SelectionContext`의 주입 항목이 하나 줄었다).
|
|
81
|
+
* `selection.ts` 헤더가 *"세 번째 소비자가 생길 때"*로 적어 둔 트리거의 실제 발동 사유는
|
|
82
|
+
* 개수가 아니라 **팩토리가 소비자에서 빠진 것**이었다.
|
|
83
|
+
*/
|
|
84
|
+
export declare function groupMoveCommands(state: EditorState, groupId: ModelId, location: Point, members: {
|
|
85
|
+
id: ModelId;
|
|
86
|
+
location: Point;
|
|
87
|
+
}[]): Command[];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { Command, EditorState } from '../command/types';
|
|
3
|
+
import { EditorController } from './controller';
|
|
4
|
+
import { ModelId } from '../core/types';
|
|
5
|
+
/** 이 축이 팩토리 클로저에서 쓰는 것 전부. 늘어나면 여기 선언이 먼저 늘어난다(= 의존 인벤토리). */
|
|
6
|
+
export interface EntityContext {
|
|
7
|
+
/** 편집 대상 reactive 상태(속성만 교체되므로 참조 안정). */
|
|
8
|
+
state: EditorState;
|
|
9
|
+
/** 조회 모드 판정 — `addEntity`가 `null`을 돌려주려면 run()의 no-op 백스톱보다 앞에서 봐야 한다. */
|
|
10
|
+
editable: Ref<boolean>;
|
|
11
|
+
/** 모델 변경의 단일 실행점(조회 모드 no-op + 안내). */
|
|
12
|
+
run: (c: Command) => void;
|
|
13
|
+
/** 잠금 게이트 — 차단 시 true + 안내 emit(사용자 intent 경로). */
|
|
14
|
+
gateEntityLocked: (id: ModelId) => boolean;
|
|
15
|
+
/** 순수 잠금 조회 — 공개 질의의 위임 대상. **안내를 내지 않는다**(위 ⚠️ 참고). */
|
|
16
|
+
isEntityLockedFn: (id: ModelId) => boolean;
|
|
17
|
+
isAssocLockedFn: (assocId: ModelId) => boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function createEntityApi(ctx: EntityContext): Pick<EditorController, 'addEntity' | 'renameEntity' | 'updateEntity' | 'moveEntity' | 'resizeEntity' | 'removeEntity' | 'setEntitySwatch' | 'setEntityCollapsed' | 'setEntityLocked' | 'isEntityLocked' | 'isAssociationLocked' | 'collapseAll' | 'expandAll'>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { Command, EditorState } from '../command/types';
|
|
3
|
+
import { EditorController, Selection } from './controller';
|
|
4
|
+
import { ModelId } from '../core/types';
|
|
5
|
+
/** 이 축이 팩토리 클로저에서 쓰는 것 전부. 늘어나면 여기 선언이 먼저 늘어난다(= 의존 인벤토리). */
|
|
6
|
+
export interface GroupContext {
|
|
7
|
+
/** 편집 대상 reactive 상태(속성만 교체되므로 참조 안정). */
|
|
8
|
+
state: EditorState;
|
|
9
|
+
/** 조회 모드 판정 — add류가 `null`을 돌려주려면 run()의 no-op 백스톱보다 앞에서 봐야 한다. */
|
|
10
|
+
editable: Ref<boolean>;
|
|
11
|
+
/** 모델 변경의 단일 실행점(조회 모드 no-op + 안내). */
|
|
12
|
+
run: (c: Command) => void;
|
|
13
|
+
/** 그룹 생성 후 선택 해제(사라진 엔티티 선택을 남기지 않는다). */
|
|
14
|
+
selection: Ref<Selection>;
|
|
15
|
+
/** 잠금 게이트(엔티티) — `dropEntity`가 옮기는 대상이 엔티티라서 필요하다. */
|
|
16
|
+
gateEntityLocked: (id: ModelId) => boolean;
|
|
17
|
+
/** 잠금 게이트(그룹) — 차단 시 true + 안내 emit. */
|
|
18
|
+
gateGroupLocked: (groupId: ModelId) => boolean;
|
|
19
|
+
/** 순수 잠금 조회 — 공개 질의 `isGroupLocked`의 위임 대상. **안내를 내지 않는다**(위 ⚠️). */
|
|
20
|
+
isGroupLockedFn: (groupId: ModelId) => boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function createGroupApi(ctx: GroupContext): Pick<EditorController, 'dragGroup' | 'resizeGroup' | 'setGroupSwatch' | 'setGroupLocked' | 'isGroupLocked' | 'updateGroup' | 'createGroup' | 'addEmptyGroup' | 'removeGroup' | 'dropEntity' | 'ungroupEntity' | 'dropNote'>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { Command } from '../command/types';
|
|
3
|
+
import { EditorController } from './controller';
|
|
4
|
+
/** 이 축이 팩토리 클로저에서 쓰는 것 전부. 늘어나면 여기 선언이 먼저 늘어난다(= 의존 인벤토리). */
|
|
5
|
+
export interface NoteContext {
|
|
6
|
+
/** 조회 모드 판정 — `addNote`가 `null`을 돌려주려면 run()의 no-op 백스톱보다 앞에서 봐야 한다. */
|
|
7
|
+
editable: Ref<boolean>;
|
|
8
|
+
/** 모델 변경의 단일 실행점(조회 모드 no-op + 안내). */
|
|
9
|
+
run: (c: Command) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function createNoteApi(ctx: NoteContext): Pick<EditorController, 'addNote' | 'removeNote' | 'moveNote' | 'resizeNote' | 'setNoteMemo' | 'setNoteSwatch' | 'addNoteConnection' | 'removeNoteConnection' | 'moveNoteConnectionWaypoint' | 'addNoteConnectionWaypoint' | 'removeNoteConnectionWaypoint' | 'clearNoteConnectionWaypoints'>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Ref } from 'vue';
|
|
2
2
|
import { Command, EditorState } from '../command/types';
|
|
3
3
|
import { EditorController, Selection } from './controller';
|
|
4
|
-
import { ModelId
|
|
4
|
+
import { ModelId } from '../core/types';
|
|
5
5
|
/** 이 축이 팩토리 클로저에서 쓰는 것 전부. 늘어나면 여기 선언이 먼저 늘어난다(= 의존 인벤토리). */
|
|
6
6
|
export interface SelectionContext {
|
|
7
7
|
state: EditorState;
|
|
@@ -18,10 +18,5 @@ export interface SelectionContext {
|
|
|
18
18
|
/** 순수 잠금 조회(다중 이동에서 잠긴 대상만 건너뛴다 — 안내는 내지 않는다). */
|
|
19
19
|
isEntityLockedFn: (id: ModelId) => boolean;
|
|
20
20
|
isGroupLockedFn: (id: ModelId) => boolean;
|
|
21
|
-
/** 그룹 박스 + 멤버 + 내부 waypoint를 같은 delta로 옮기는 명령 집합(dragGroup과 공유). */
|
|
22
|
-
groupMoveCommands: (groupId: ModelId, location: Point, members: {
|
|
23
|
-
id: ModelId;
|
|
24
|
-
location: Point;
|
|
25
|
-
}[]) => Command[];
|
|
26
21
|
}
|
|
27
22
|
export declare function createSelectionApi(ctx: SelectionContext): Pick<EditorController, 'selectAttribute' | 'moveAttributeFocus' | 'nudgeSelectedAttributes' | 'nudgeNodes' | 'requestFocus'>;
|