@yanqirenshi/model.tm 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +143 -2
- package/dist/check.d.ts +18 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +98 -0
- package/dist/cjs/check.js +102 -0
- package/dist/cjs/defaults.js +145 -0
- package/dist/cjs/fields.js +77 -0
- package/dist/cjs/index.js +56 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/patch.js +174 -0
- package/dist/cjs/schema.js +179 -0
- package/dist/cjs/types.js +8 -0
- package/dist/defaults.d.ts +67 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +133 -0
- package/dist/fields.d.ts +19 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +72 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/patch.d.ts +21 -0
- package/dist/patch.d.ts.map +1 -0
- package/dist/patch.js +164 -0
- package/dist/schema.d.ts +768 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +176 -0
- package/dist/types.d.ts +129 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/package.json +55 -5
- package/src/check.ts +126 -0
- package/src/defaults.ts +172 -0
- package/src/fields.ts +82 -0
- package/src/index.ts +31 -0
- package/src/patch.ts +206 -0
- package/src/schema.ts +194 -0
- package/src/types.ts +156 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// model.tm — TM(T字形ER。d3.ter)の「図ごとの知識」。描画はしない(react / d3 に依存しない)。
|
|
3
|
+
//
|
|
4
|
+
// スキーマ: SCHEMAS / *_SCHEMA(JSON Schema 2020-12。4 コレクション)
|
|
5
|
+
// 整合性ルール: check(data)(id の重複・参照先の存在・CLASS と mapping の結線の規則)
|
|
6
|
+
// 既定値の補完: withDefaults(record) / entityWithDefaults / relationshipWithDefaults / kindOf / nameOf
|
|
7
|
+
// 種別の表示: ENTITY_TYPES / TYPE_BADGES / TYPE_COLORS(d3.ter が読む)
|
|
8
|
+
// 編集できる項目: fieldsOf(record, collection?) / nameFields / ENTITY_FIELDS / RELATIONSHIP_FIELDS / MASTER_FIELDS
|
|
9
|
+
// patch への変換: movePatch(entity, move) / applyPatch(record, values, collection?) / mergePatch(record, patch)
|
|
10
|
+
//
|
|
11
|
+
// view(d3.ter)はこのパッケージの既定値(種別バッジ・配色・角度)を読む。インスペクタ(colonoscope)との間に横の依存は無い。
|
|
12
|
+
// ModelError / mergePatch / getByPath / movePatch と入力の読み取り部品は model.core(#151)のもの。
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.applyPatch = exports.movePatch = exports.mergePatch = exports.getByPath = exports.titleOf = exports.collectionOf = exports.ModelError = exports.fieldsOf = exports.nameFields = exports.MASTER_FIELDS = exports.RELATIONSHIP_FIELDS = exports.ENTITY_FIELDS = exports.findById = exports.check = exports.RELATIONSHIPS_SCHEMA = exports.ENTITIES_SCHEMA = exports.ATTRIBUTES_SCHEMA = exports.IDENTIFIERS_SCHEMA = exports.SCHEMAS = exports.withDefaults = exports.relationshipWithDefaults = exports.entityWithDefaults = exports.endWithDefaults = exports.nameOf = exports.kindOf = exports.isEntity = exports.isRelationship = exports.isEntityType = exports.RELATIONSHIP_DEFAULTS = exports.ENTITY_DEFAULTS = exports.OPTIONALITIES = exports.CARDINALITIES = exports.SUBSET_KINDS = exports.MAPPING_TYPES = exports.TYPE_COLORS = exports.TYPE_BADGES = exports.ENTITY_TYPES = void 0;
|
|
15
|
+
var defaults_js_1 = require("./defaults.js");
|
|
16
|
+
Object.defineProperty(exports, "ENTITY_TYPES", { enumerable: true, get: function () { return defaults_js_1.ENTITY_TYPES; } });
|
|
17
|
+
Object.defineProperty(exports, "TYPE_BADGES", { enumerable: true, get: function () { return defaults_js_1.TYPE_BADGES; } });
|
|
18
|
+
Object.defineProperty(exports, "TYPE_COLORS", { enumerable: true, get: function () { return defaults_js_1.TYPE_COLORS; } });
|
|
19
|
+
Object.defineProperty(exports, "MAPPING_TYPES", { enumerable: true, get: function () { return defaults_js_1.MAPPING_TYPES; } });
|
|
20
|
+
Object.defineProperty(exports, "SUBSET_KINDS", { enumerable: true, get: function () { return defaults_js_1.SUBSET_KINDS; } });
|
|
21
|
+
Object.defineProperty(exports, "CARDINALITIES", { enumerable: true, get: function () { return defaults_js_1.CARDINALITIES; } });
|
|
22
|
+
Object.defineProperty(exports, "OPTIONALITIES", { enumerable: true, get: function () { return defaults_js_1.OPTIONALITIES; } });
|
|
23
|
+
Object.defineProperty(exports, "ENTITY_DEFAULTS", { enumerable: true, get: function () { return defaults_js_1.ENTITY_DEFAULTS; } });
|
|
24
|
+
Object.defineProperty(exports, "RELATIONSHIP_DEFAULTS", { enumerable: true, get: function () { return defaults_js_1.RELATIONSHIP_DEFAULTS; } });
|
|
25
|
+
Object.defineProperty(exports, "isEntityType", { enumerable: true, get: function () { return defaults_js_1.isEntityType; } });
|
|
26
|
+
Object.defineProperty(exports, "isRelationship", { enumerable: true, get: function () { return defaults_js_1.isRelationship; } });
|
|
27
|
+
Object.defineProperty(exports, "isEntity", { enumerable: true, get: function () { return defaults_js_1.isEntity; } });
|
|
28
|
+
Object.defineProperty(exports, "kindOf", { enumerable: true, get: function () { return defaults_js_1.kindOf; } });
|
|
29
|
+
Object.defineProperty(exports, "nameOf", { enumerable: true, get: function () { return defaults_js_1.nameOf; } });
|
|
30
|
+
Object.defineProperty(exports, "endWithDefaults", { enumerable: true, get: function () { return defaults_js_1.endWithDefaults; } });
|
|
31
|
+
Object.defineProperty(exports, "entityWithDefaults", { enumerable: true, get: function () { return defaults_js_1.entityWithDefaults; } });
|
|
32
|
+
Object.defineProperty(exports, "relationshipWithDefaults", { enumerable: true, get: function () { return defaults_js_1.relationshipWithDefaults; } });
|
|
33
|
+
Object.defineProperty(exports, "withDefaults", { enumerable: true, get: function () { return defaults_js_1.withDefaults; } });
|
|
34
|
+
var schema_js_1 = require("./schema.js");
|
|
35
|
+
Object.defineProperty(exports, "SCHEMAS", { enumerable: true, get: function () { return schema_js_1.SCHEMAS; } });
|
|
36
|
+
Object.defineProperty(exports, "IDENTIFIERS_SCHEMA", { enumerable: true, get: function () { return schema_js_1.IDENTIFIERS_SCHEMA; } });
|
|
37
|
+
Object.defineProperty(exports, "ATTRIBUTES_SCHEMA", { enumerable: true, get: function () { return schema_js_1.ATTRIBUTES_SCHEMA; } });
|
|
38
|
+
Object.defineProperty(exports, "ENTITIES_SCHEMA", { enumerable: true, get: function () { return schema_js_1.ENTITIES_SCHEMA; } });
|
|
39
|
+
Object.defineProperty(exports, "RELATIONSHIPS_SCHEMA", { enumerable: true, get: function () { return schema_js_1.RELATIONSHIPS_SCHEMA; } });
|
|
40
|
+
var check_js_1 = require("./check.js");
|
|
41
|
+
Object.defineProperty(exports, "check", { enumerable: true, get: function () { return check_js_1.check; } });
|
|
42
|
+
Object.defineProperty(exports, "findById", { enumerable: true, get: function () { return check_js_1.findById; } });
|
|
43
|
+
var fields_js_1 = require("./fields.js");
|
|
44
|
+
Object.defineProperty(exports, "ENTITY_FIELDS", { enumerable: true, get: function () { return fields_js_1.ENTITY_FIELDS; } });
|
|
45
|
+
Object.defineProperty(exports, "RELATIONSHIP_FIELDS", { enumerable: true, get: function () { return fields_js_1.RELATIONSHIP_FIELDS; } });
|
|
46
|
+
Object.defineProperty(exports, "MASTER_FIELDS", { enumerable: true, get: function () { return fields_js_1.MASTER_FIELDS; } });
|
|
47
|
+
Object.defineProperty(exports, "nameFields", { enumerable: true, get: function () { return fields_js_1.nameFields; } });
|
|
48
|
+
Object.defineProperty(exports, "fieldsOf", { enumerable: true, get: function () { return fields_js_1.fieldsOf; } });
|
|
49
|
+
var patch_js_1 = require("./patch.js");
|
|
50
|
+
Object.defineProperty(exports, "ModelError", { enumerable: true, get: function () { return patch_js_1.ModelError; } });
|
|
51
|
+
Object.defineProperty(exports, "collectionOf", { enumerable: true, get: function () { return patch_js_1.collectionOf; } });
|
|
52
|
+
Object.defineProperty(exports, "titleOf", { enumerable: true, get: function () { return patch_js_1.titleOf; } });
|
|
53
|
+
Object.defineProperty(exports, "getByPath", { enumerable: true, get: function () { return patch_js_1.getByPath; } });
|
|
54
|
+
Object.defineProperty(exports, "mergePatch", { enumerable: true, get: function () { return patch_js_1.mergePatch; } });
|
|
55
|
+
Object.defineProperty(exports, "movePatch", { enumerable: true, get: function () { return patch_js_1.movePatch; } });
|
|
56
|
+
Object.defineProperty(exports, "applyPatch", { enumerable: true, get: function () { return patch_js_1.applyPatch; } });
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// UI の操作(ドラッグ・インスペクタの適用)を、保存する patch(JSON Merge Patch)に変換する。
|
|
3
|
+
//
|
|
4
|
+
// 戻り値は { collection, id, patch }。利用側(iHub など)は図の種類を知らずにこれを保存すればよい。
|
|
5
|
+
// 入力の検証に失敗したときは ModelError を投げる(メッセージは利用者にそのまま見せられる日本語)。
|
|
6
|
+
// 使い方の誤り(マスタなのに collection を渡していない)は ModelError ではなく Error。
|
|
7
|
+
// 読み取り部品(toLength など)と patch の道具は model.core にある(#151)。
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.mergePatch = exports.getByPath = exports.ModelError = void 0;
|
|
10
|
+
exports.collectionOf = collectionOf;
|
|
11
|
+
exports.titleOf = titleOf;
|
|
12
|
+
exports.movePatch = movePatch;
|
|
13
|
+
exports.applyPatch = applyPatch;
|
|
14
|
+
const model_core_1 = require("@yanqirenshi/model.core");
|
|
15
|
+
const defaults_js_1 = require("./defaults.js");
|
|
16
|
+
const fields_js_1 = require("./fields.js");
|
|
17
|
+
// model.core のものをそのまま公開する(利用側が model.tm だけを読めばよいように)
|
|
18
|
+
var model_core_2 = require("@yanqirenshi/model.core");
|
|
19
|
+
Object.defineProperty(exports, "ModelError", { enumerable: true, get: function () { return model_core_2.ModelError; } });
|
|
20
|
+
Object.defineProperty(exports, "getByPath", { enumerable: true, get: function () { return model_core_2.getByPath; } });
|
|
21
|
+
Object.defineProperty(exports, "mergePatch", { enumerable: true, get: function () { return model_core_2.mergePatch; } });
|
|
22
|
+
/**
|
|
23
|
+
* レコードを置くコレクション。関係・エンティティは形から決まる。
|
|
24
|
+
* マスタは identifiers / attributes を形から判別できないので collection が要る。
|
|
25
|
+
*/
|
|
26
|
+
function collectionOf(record, collection) {
|
|
27
|
+
if ((0, defaults_js_1.isRelationship)(record))
|
|
28
|
+
return 'relationships';
|
|
29
|
+
if ((0, defaults_js_1.isEntity)(record))
|
|
30
|
+
return 'entities';
|
|
31
|
+
if (!collection)
|
|
32
|
+
throw new Error('model.tm: マスタ (識別子・属性) のレコードには collection を渡してください。');
|
|
33
|
+
return collection;
|
|
34
|
+
}
|
|
35
|
+
/** インスペクタの見出し。名前、無ければ id(関係はラベル、無ければ「種類 id」) */
|
|
36
|
+
function titleOf(record) {
|
|
37
|
+
if ((0, defaults_js_1.isRelationship)(record)) {
|
|
38
|
+
if (typeof record.label === 'string' && record.label !== '')
|
|
39
|
+
return record.label;
|
|
40
|
+
return `${record.type || ''} ${String(record.id)}`.trim();
|
|
41
|
+
}
|
|
42
|
+
const name = (0, defaults_js_1.nameOf)(record);
|
|
43
|
+
return name !== '' ? name : String(record.id);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* ドラッグで動かしたエンティティの位置を保存する patch。
|
|
47
|
+
* 保存してある position に移動量を足し、整数に丸める(position が無いときは 0, 0 から)。z は触らない。
|
|
48
|
+
*/
|
|
49
|
+
function movePatch(entity, move) {
|
|
50
|
+
return (0, model_core_1.movePatch)(entity, move, 'entities');
|
|
51
|
+
}
|
|
52
|
+
// インスペクタの入力のうち、図に描いている値(withDefaults)から変わった項目だけ
|
|
53
|
+
function changedValues(record, values, collection) {
|
|
54
|
+
return (0, model_core_1.changedValues)((0, defaults_js_1.withDefaults)(record), values, (0, fields_js_1.fieldsOf)(record, collection));
|
|
55
|
+
}
|
|
56
|
+
// 幅・高さは 0 以上(0 は「内容に合わせる」)
|
|
57
|
+
const LENGTH = { hint: '(0 で内容に合わせる)' };
|
|
58
|
+
// 名前(name / name.logical / name.physical)。required なら空にできない
|
|
59
|
+
function namePatch(patch, path, value, required) {
|
|
60
|
+
// name と name.logical は空にできない。name.physical は空にできる(論理名だけのモデル)
|
|
61
|
+
if (value === '' && required)
|
|
62
|
+
throw new model_core_1.ModelError('名称を入力してください。');
|
|
63
|
+
(0, model_core_1.put)(patch, path, value);
|
|
64
|
+
}
|
|
65
|
+
// エンティティの入力 → patch(name / type / description / size)
|
|
66
|
+
function entityPatch(entity, values) {
|
|
67
|
+
const patch = {};
|
|
68
|
+
for (const [path, value] of changedValues(entity, values)) {
|
|
69
|
+
switch (path) {
|
|
70
|
+
case 'name':
|
|
71
|
+
case 'name.logical':
|
|
72
|
+
namePatch(patch, path, value, true);
|
|
73
|
+
break;
|
|
74
|
+
case 'name.physical':
|
|
75
|
+
namePatch(patch, path, value, false);
|
|
76
|
+
break;
|
|
77
|
+
case 'type':
|
|
78
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toOption)(value, defaults_js_1.ENTITY_TYPES, '種別'));
|
|
79
|
+
break;
|
|
80
|
+
case 'size.w':
|
|
81
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toLength)(value, '幅', LENGTH));
|
|
82
|
+
break;
|
|
83
|
+
case 'size.h':
|
|
84
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toLength)(value, '高さ', LENGTH));
|
|
85
|
+
break;
|
|
86
|
+
case 'description':
|
|
87
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toOptionalText)(value));
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return patch;
|
|
92
|
+
}
|
|
93
|
+
const END_LABELS = { from: '接続元', to: '接続先' };
|
|
94
|
+
// 関係の入力 → patch(type / label / from / to / subset / description)
|
|
95
|
+
function relationshipPatch(relationship, values) {
|
|
96
|
+
const patch = {};
|
|
97
|
+
for (const [path, value] of changedValues(relationship, values)) {
|
|
98
|
+
const [head, key] = path.split('.');
|
|
99
|
+
if ((head === 'from' || head === 'to') && key) {
|
|
100
|
+
const label = END_LABELS[head];
|
|
101
|
+
switch (key) {
|
|
102
|
+
case 'position':
|
|
103
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toDegree)(value, `${label}の位置`));
|
|
104
|
+
break;
|
|
105
|
+
case 'cardinality':
|
|
106
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toOptionNumberOrNull)(value, defaults_js_1.CARDINALITIES, `${label}のカーディナリティ`));
|
|
107
|
+
break;
|
|
108
|
+
case 'optionality':
|
|
109
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toOptionNumberOrNull)(value, defaults_js_1.OPTIONALITIES, `${label}のオプショナリティ`));
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
switch (path) {
|
|
115
|
+
case 'subset.kind':
|
|
116
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toOption)(value, defaults_js_1.SUBSET_KINDS, 'サブセットの区分'));
|
|
117
|
+
break;
|
|
118
|
+
case 'subset.code':
|
|
119
|
+
// 区分コードを空にするとサブセットの表記を消す(subset ごと除く)
|
|
120
|
+
if (value === '')
|
|
121
|
+
patch.subset = null;
|
|
122
|
+
else
|
|
123
|
+
(0, model_core_1.put)(patch, path, value);
|
|
124
|
+
break;
|
|
125
|
+
case 'type':
|
|
126
|
+
case 'label':
|
|
127
|
+
case 'description':
|
|
128
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toOptionalText)(value));
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// subset を除くときは kind の変更も要らない
|
|
133
|
+
if (patch.subset === null)
|
|
134
|
+
return patch;
|
|
135
|
+
// kind だけを新しく書いて code が無い subset は作らない(d3.ter は code が無ければ描かない)
|
|
136
|
+
const subset = patch.subset;
|
|
137
|
+
if (subset && subset.kind !== undefined && subset.code === undefined && !relationship.subset?.code)
|
|
138
|
+
throw new model_core_1.ModelError('サブセットの区分コードを入力してください。');
|
|
139
|
+
return patch;
|
|
140
|
+
}
|
|
141
|
+
// マスタの入力 → patch(name / description)
|
|
142
|
+
function masterPatch(master, values, collection) {
|
|
143
|
+
const patch = {};
|
|
144
|
+
for (const [path, value] of changedValues(master, values, collection)) {
|
|
145
|
+
switch (path) {
|
|
146
|
+
case 'name':
|
|
147
|
+
case 'name.logical':
|
|
148
|
+
// 識別子・属性の名前は空にできない(エンティティの行に描く文字が無くなる)
|
|
149
|
+
namePatch(patch, path, value, true);
|
|
150
|
+
break;
|
|
151
|
+
case 'name.physical':
|
|
152
|
+
namePatch(patch, path, value, false);
|
|
153
|
+
break;
|
|
154
|
+
case 'description':
|
|
155
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toOptionalText)(value));
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return patch;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* インスペクタの「適用」の値を、保存する patch に変換する。
|
|
163
|
+
* 図に描いている値から変えた項目だけを patch に入れる(変えていない既定の値まで書き込まないため)。
|
|
164
|
+
* 変更が無ければ patch は {}。マスタのときは collection(identifiers / attributes)が要る。
|
|
165
|
+
*/
|
|
166
|
+
function applyPatch(record, values, collection) {
|
|
167
|
+
const target = collectionOf(record, collection);
|
|
168
|
+
const patch = (0, defaults_js_1.kindOf)(record) === 'relationship'
|
|
169
|
+
? relationshipPatch(record, values)
|
|
170
|
+
: (0, defaults_js_1.kindOf)(record) === 'entity'
|
|
171
|
+
? entityPatch(record, values)
|
|
172
|
+
: masterPatch(record, values, target);
|
|
173
|
+
return { collection: target, id: record.id, patch };
|
|
174
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// TM(d3.ter)の入力データの JSON Schema(2020-12)。コレクションごとに 1 つ。
|
|
3
|
+
//
|
|
4
|
+
// iHub の server/schemas/tm/*.schema.json を移したもの。iHub 版と違い additionalProperties を閉じていない
|
|
5
|
+
// (利用側の項目を落とさないため)。検査するのは、図の構造にかかわる項目(id・type・参照・position・size・
|
|
6
|
+
// 関係の端点・subset・mapping)。name は文字列でも { logical, physical } でもよい。
|
|
7
|
+
//
|
|
8
|
+
// x-id-start はスキーマの検証には使わない注釈(コレクションが空のときに最初に振る id)。
|
|
9
|
+
// Ajv で使うときは addKeyword({ keyword: 'x-id-start', schemaType: 'number' }) を足す。
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.SCHEMAS = exports.RELATIONSHIPS_SCHEMA = exports.ENTITIES_SCHEMA = exports.ATTRIBUTES_SCHEMA = exports.IDENTIFIERS_SCHEMA = void 0;
|
|
12
|
+
const defaults_js_1 = require("./defaults.js");
|
|
13
|
+
const ID = { type: ['integer', 'string'] };
|
|
14
|
+
const NAME = {
|
|
15
|
+
description: '文字列、または論理名と物理名の組',
|
|
16
|
+
oneOf: [
|
|
17
|
+
{ type: 'string' },
|
|
18
|
+
{
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
logical: { type: 'string' },
|
|
22
|
+
physical: { type: 'string' },
|
|
23
|
+
description: { type: 'string' },
|
|
24
|
+
},
|
|
25
|
+
additionalProperties: true,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
// マスタ(identifiers / attributes)の共通形
|
|
30
|
+
function masterSchema(title, description, idStart) {
|
|
31
|
+
return {
|
|
32
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
33
|
+
title,
|
|
34
|
+
description,
|
|
35
|
+
'x-id-start': idStart,
|
|
36
|
+
type: 'array',
|
|
37
|
+
items: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {
|
|
40
|
+
id: ID,
|
|
41
|
+
name: NAME,
|
|
42
|
+
description: { type: ['string', 'null'] },
|
|
43
|
+
},
|
|
44
|
+
required: ['id', 'name'],
|
|
45
|
+
additionalProperties: true,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
exports.IDENTIFIERS_SCHEMA = masterSchema('TM の識別子のマスタ', '識別子 (個体指定子) のマスタ。entities[].identifiers[].identifier から id で参照される。', 10000);
|
|
50
|
+
exports.ATTRIBUTES_SCHEMA = masterSchema('TM の属性のマスタ', '属性のマスタ。entities[].attributes[].attribute から id で参照される。', 20000);
|
|
51
|
+
// エンティティが持つインスタンス(識別子・属性)の共通形。ref はマスタを指す項目名
|
|
52
|
+
function instanceSchema(ref) {
|
|
53
|
+
return {
|
|
54
|
+
type: 'array',
|
|
55
|
+
items: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties: {
|
|
58
|
+
id: ID,
|
|
59
|
+
[ref]: ID,
|
|
60
|
+
name: NAME,
|
|
61
|
+
description: { type: ['string', 'null'] },
|
|
62
|
+
},
|
|
63
|
+
required: ['id', ref],
|
|
64
|
+
additionalProperties: true,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
exports.ENTITIES_SCHEMA = {
|
|
69
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
70
|
+
title: 'TM のエンティティ',
|
|
71
|
+
description: 'TM (T字形ER) のエンティティ。type は 10 種の種別 (これ以外は d3.ter が描画時に例外にする)。識別子・属性はマスタの id を参照するインスタンスとして持ち、インスタンスの id は全エンティティを通して一意 (関係の details がこれを指す)。name は文字列か論理名・物理名の組。position はドラッグで書き換わる。size の w / h が 0 のときは内容に合わせる。',
|
|
72
|
+
'x-id-start': 30000,
|
|
73
|
+
type: 'array',
|
|
74
|
+
items: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
properties: {
|
|
77
|
+
id: ID,
|
|
78
|
+
type: { enum: [...defaults_js_1.ENTITY_TYPES] },
|
|
79
|
+
name: NAME,
|
|
80
|
+
description: { type: ['string', 'null'] },
|
|
81
|
+
position: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {
|
|
84
|
+
x: { type: 'number' },
|
|
85
|
+
y: { type: 'number' },
|
|
86
|
+
z: { type: 'number' },
|
|
87
|
+
},
|
|
88
|
+
required: ['x', 'y'],
|
|
89
|
+
additionalProperties: false,
|
|
90
|
+
},
|
|
91
|
+
size: {
|
|
92
|
+
type: 'object',
|
|
93
|
+
properties: {
|
|
94
|
+
w: { type: 'number', minimum: 0 },
|
|
95
|
+
h: { type: 'number', minimum: 0 },
|
|
96
|
+
},
|
|
97
|
+
required: ['w', 'h'],
|
|
98
|
+
additionalProperties: false,
|
|
99
|
+
},
|
|
100
|
+
identifiers: instanceSchema('identifier'),
|
|
101
|
+
attributes: instanceSchema('attribute'),
|
|
102
|
+
},
|
|
103
|
+
required: ['id', 'type', 'name'],
|
|
104
|
+
additionalProperties: true,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
exports.RELATIONSHIPS_SCHEMA = {
|
|
108
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
109
|
+
title: 'TM のリレーションシップ',
|
|
110
|
+
description: 'エンティティの間の結線。from.entity / to.entity はエンティティの id (同じエンティティを指すと自己結線 = 再帰のループ)。端点の cardinality (1 / 3) と optionality (0 / 1) は無ければ記号を描かない。position は接続位置の角度 (0=真下・時計回り)。details は線を取り付けるインスタンス (省略すると先頭の識別子)。subset はサブセット結線の区分コード (same は =、different は ×)。mapping は結線の中点から垂下する対応表・対照表・再帰表 (再帰表は自己結線にだけ)。',
|
|
111
|
+
'x-id-start': 1,
|
|
112
|
+
type: 'array',
|
|
113
|
+
items: {
|
|
114
|
+
type: 'object',
|
|
115
|
+
properties: {
|
|
116
|
+
id: ID,
|
|
117
|
+
type: { type: ['string', 'null'] },
|
|
118
|
+
from: { $ref: '#/$defs/end' },
|
|
119
|
+
to: { $ref: '#/$defs/end' },
|
|
120
|
+
details: {
|
|
121
|
+
type: 'array',
|
|
122
|
+
items: {
|
|
123
|
+
type: 'object',
|
|
124
|
+
properties: {
|
|
125
|
+
from: { $ref: '#/$defs/detail_end' },
|
|
126
|
+
to: { $ref: '#/$defs/detail_end' },
|
|
127
|
+
},
|
|
128
|
+
required: ['from', 'to'],
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
subset: {
|
|
132
|
+
type: ['object', 'null'],
|
|
133
|
+
properties: {
|
|
134
|
+
kind: { enum: [...defaults_js_1.SUBSET_KINDS] },
|
|
135
|
+
code: { type: 'string' },
|
|
136
|
+
},
|
|
137
|
+
required: ['kind', 'code'],
|
|
138
|
+
},
|
|
139
|
+
mapping: {
|
|
140
|
+
type: ['object', 'null'],
|
|
141
|
+
properties: { entity: ID },
|
|
142
|
+
required: ['entity'],
|
|
143
|
+
},
|
|
144
|
+
label: { type: ['string', 'null'] },
|
|
145
|
+
description: { type: ['string', 'null'] },
|
|
146
|
+
},
|
|
147
|
+
required: ['id', 'from', 'to'],
|
|
148
|
+
additionalProperties: true,
|
|
149
|
+
},
|
|
150
|
+
$defs: {
|
|
151
|
+
end: {
|
|
152
|
+
type: 'object',
|
|
153
|
+
properties: {
|
|
154
|
+
entity: ID,
|
|
155
|
+
cardinality: { enum: [...defaults_js_1.CARDINALITIES], description: '1 か 多 (3)。無ければ記号を描かない' },
|
|
156
|
+
optionality: { enum: [...defaults_js_1.OPTIONALITIES], description: '0 は任意 (○)、1 は必須 (横棒)。無ければ記号を描かない' },
|
|
157
|
+
position: { type: 'number', description: '接続位置の角度。0=真下・時計回り (90=左 / 180=真上 / 270=右)' },
|
|
158
|
+
id: { ...ID, description: '旧来の項目。端点の識別子のインスタンスの id (details に置き換わった)' },
|
|
159
|
+
},
|
|
160
|
+
required: ['entity'],
|
|
161
|
+
additionalProperties: true,
|
|
162
|
+
},
|
|
163
|
+
detail_end: {
|
|
164
|
+
type: 'object',
|
|
165
|
+
properties: {
|
|
166
|
+
id: ID,
|
|
167
|
+
description: { type: ['string', 'null'] },
|
|
168
|
+
},
|
|
169
|
+
required: ['id'],
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
/** コレクション名 → スキーマ */
|
|
174
|
+
exports.SCHEMAS = {
|
|
175
|
+
identifiers: exports.IDENTIFIERS_SCHEMA,
|
|
176
|
+
attributes: exports.ATTRIBUTES_SCHEMA,
|
|
177
|
+
entities: exports.ENTITIES_SCHEMA,
|
|
178
|
+
relationships: exports.RELATIONSHIPS_SCHEMA,
|
|
179
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// model.tm の公開型。
|
|
3
|
+
//
|
|
4
|
+
// ここで言う「レコード」は、d3.ter の data() に渡す入力そのものの 1 要素。
|
|
5
|
+
// { identifiers, attributes, entities, relationships }
|
|
6
|
+
// 形は model.er(ER 図)と同じ階層形式で、TM 固有の項目(エンティティの type、関係の subset / mapping / label)が足されている。
|
|
7
|
+
// d3.ter が正規化したあとの datum(_id / _core を持つ Atman)ではない。
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Position, Size } from '@yanqirenshi/types';
|
|
2
|
+
import type { TmCardinality, TmEntityRecord, TmEntityType, TmKind, TmMasterRecord, TmOptionality, TmRecord, TmRelationshipEnd, TmRelationshipRecord } from './types.js';
|
|
3
|
+
/** エンティティの種別(10 種) */
|
|
4
|
+
export declare const ENTITY_TYPES: readonly TmEntityType[];
|
|
5
|
+
/** 種別バッジ(箱のヘッダ右に描く文字。CLASS は意図的に無し = '') */
|
|
6
|
+
export declare const TYPE_BADGES: Record<TmEntityType, string>;
|
|
7
|
+
/** 種別ごとの箱の背景色 */
|
|
8
|
+
export declare const TYPE_COLORS: Record<TmEntityType, string>;
|
|
9
|
+
/** 結線の中点から垂下(mapping)できる種別 */
|
|
10
|
+
export declare const MAPPING_TYPES: readonly TmEntityType[];
|
|
11
|
+
/** サブセット結線の区分コードの種類 */
|
|
12
|
+
export declare const SUBSET_KINDS: readonly ["same", "different"];
|
|
13
|
+
/** カーディナリティ(1 か 多) */
|
|
14
|
+
export declare const CARDINALITIES: readonly TmCardinality[];
|
|
15
|
+
/** オプショナリティ(0 は任意、1 は必須) */
|
|
16
|
+
export declare const OPTIONALITIES: readonly TmOptionality[];
|
|
17
|
+
/** エンティティの既定。size の 0 は「内容に合わせる」 */
|
|
18
|
+
export declare const ENTITY_DEFAULTS: {
|
|
19
|
+
readonly position: Position;
|
|
20
|
+
readonly size: Size;
|
|
21
|
+
};
|
|
22
|
+
/** 関係の既定。端点の角度は 0(真下)。cardinality / optionality は既定なし(無ければ記号を描かない) */
|
|
23
|
+
export declare const RELATIONSHIP_DEFAULTS: {
|
|
24
|
+
readonly end: {
|
|
25
|
+
readonly position: 0;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
/** 種別として正しいか */
|
|
29
|
+
export declare function isEntityType(value: unknown): value is TmEntityType;
|
|
30
|
+
/** 関係か(from と to がエンティティを指す) */
|
|
31
|
+
export declare function isRelationship(record: TmRecord | null | undefined): record is TmRelationshipRecord;
|
|
32
|
+
/**
|
|
33
|
+
* エンティティか。関係でなく、type・インスタンスの配列・位置・大きさのどれかを持つ。
|
|
34
|
+
* マスタ(id と name だけ)と区別するための判定なので、id と name しか無いエンティティは見分けられない
|
|
35
|
+
* (entities[] の要素と分かっているときは entityWithDefaults を使う)。
|
|
36
|
+
*/
|
|
37
|
+
export declare function isEntity(record: TmRecord | null | undefined): record is TmEntityRecord;
|
|
38
|
+
/** レコードの種類 */
|
|
39
|
+
export declare function kindOf(record: TmRecord): TmKind;
|
|
40
|
+
/** 表示する名前。文字列ならそのまま、Name なら logical(無ければ physical)。無ければ '' */
|
|
41
|
+
export declare function nameOf(record: TmMasterRecord | TmEntityRecord): string;
|
|
42
|
+
/** 既定を重ねた端点(position が必ずある) */
|
|
43
|
+
export type TmFilledEnd = TmRelationshipEnd & {
|
|
44
|
+
position: number;
|
|
45
|
+
};
|
|
46
|
+
/** 端点に既定を重ねる(角度が無ければ 0。cardinality / optionality は不正値なら除く) */
|
|
47
|
+
export declare function endWithDefaults(end: TmRelationshipEnd): TmFilledEnd;
|
|
48
|
+
/** 関係に既定を重ねる: from / to の position */
|
|
49
|
+
export declare function relationshipWithDefaults<T extends TmRelationshipRecord>(record: T): T & {
|
|
50
|
+
from: TmFilledEnd;
|
|
51
|
+
to: TmFilledEnd;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* エンティティに既定を重ねる: position(無ければ 0, 0)、size(無ければ 0, 0 = 内容に合わせる)。
|
|
55
|
+
* type は補わない(無ければ無いまま。d3.ter は描けないので check で知らせる)。
|
|
56
|
+
*/
|
|
57
|
+
export declare function entityWithDefaults<T extends TmEntityRecord>(record: T): T & {
|
|
58
|
+
position: Position;
|
|
59
|
+
size: Size;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* レコードに、view が既定で使う値を重ねて返す(入力は書き換えない)。インスペクタの初期値に使う。
|
|
63
|
+
* 形から種類を決める(kindOf)。マスタはそのまま(複製だけ)。
|
|
64
|
+
* name は文字列か Name かを保つ(どちらで書いたかで編集できる項目が変わる — fieldsOf)。
|
|
65
|
+
*/
|
|
66
|
+
export declare function withDefaults<T extends TmRecord>(record: T): T;
|
|
67
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EACV,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAC5F,iBAAiB,EAAE,oBAAoB,EACxC,MAAM,YAAY,CAAC;AAEpB,sBAAsB;AACtB,eAAO,MAAM,YAAY,EAAE,SAAS,YAAY,EAG/C,CAAC;AAEF,4CAA4C;AAC5C,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAWpD,CAAC;AAEF,iBAAiB;AACjB,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAWpD,CAAC;AAEF,8BAA8B;AAC9B,eAAO,MAAM,aAAa,EAAE,SAAS,YAAY,EAAmD,CAAC;AAErG,uBAAuB;AACvB,eAAO,MAAM,YAAY,gCAAiC,CAAC;AAE3D,sBAAsB;AACtB,eAAO,MAAM,aAAa,EAAE,SAAS,aAAa,EAAW,CAAC;AAE9D,4BAA4B;AAC5B,eAAO,MAAM,aAAa,EAAE,SAAS,aAAa,EAAW,CAAC;AAE9D,oCAAoC;AACpC,eAAO,MAAM,eAAe;uBACE,QAAQ;mBACZ,IAAI;CACpB,CAAC;AAEX,sEAAsE;AACtE,eAAO,MAAM,qBAAqB;;;;CAExB,CAAC;AAEX,gBAAgB;AAChB,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAElE;AAED,gCAAgC;AAChC,wBAAgB,cAAc,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,IAAI,oBAAoB,CAKlG;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,IAAI,cAAc,CAQtF;AAED,cAAc;AACd,wBAAgB,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAK/C;AAED,8DAA8D;AAC9D,wBAAgB,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,GAAG,MAAM,CAUtE;AAED,+BAA+B;AAC/B,MAAM,MAAM,WAAW,GAAG,iBAAiB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,GAAG,EAAE,iBAAiB,GAAG,WAAW,CAanE;AAED,sCAAsC;AACtC,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,oBAAoB,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,WAAW,CAAA;CAAE,CAM9H;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,cAAc,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,CAM9G;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAQ7D"}
|
package/dist/defaults.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// 「書いていない項目」に view(d3.ter)が既定で使う値と、レコードの種類の判別。
|
|
2
|
+
//
|
|
3
|
+
// 値の出どころ: d3.ter の src/js/Entity.js(entityTypeContents = 種別バッジ、entityBackground = 配色)、
|
|
4
|
+
// Port.js(degree() の既定 0)。d3.ter はこのファイルを読む(#144)ので、ここが正。
|
|
5
|
+
// cardinality / optionality に既定は置かない(d3.ter は無ければ記号を描かない)。
|
|
6
|
+
/** エンティティの種別(10 種) */
|
|
7
|
+
export const ENTITY_TYPES = [
|
|
8
|
+
'RESOURCE', 'RESOURCE-SUBSET', 'EVENT', 'EVENT-SUBSET',
|
|
9
|
+
'COMPARATIVE', 'CORRESPONDENCE', 'RECURSION', 'MANY-VALUED-OR', 'MANY-VALUED-AND', 'CLASS',
|
|
10
|
+
];
|
|
11
|
+
/** 種別バッジ(箱のヘッダ右に描く文字。CLASS は意図的に無し = '') */
|
|
12
|
+
export const TYPE_BADGES = {
|
|
13
|
+
'RESOURCE': 'Rsc',
|
|
14
|
+
'RESOURCE-SUBSET': 'Rsc',
|
|
15
|
+
'EVENT': 'Evt',
|
|
16
|
+
'EVENT-SUBSET': 'Evt',
|
|
17
|
+
'COMPARATIVE': '対照',
|
|
18
|
+
'CORRESPONDENCE': '対応',
|
|
19
|
+
'RECURSION': '再帰',
|
|
20
|
+
'MANY-VALUED-OR': 'MO',
|
|
21
|
+
'MANY-VALUED-AND': 'MA',
|
|
22
|
+
'CLASS': '',
|
|
23
|
+
};
|
|
24
|
+
/** 種別ごとの箱の背景色 */
|
|
25
|
+
export const TYPE_COLORS = {
|
|
26
|
+
'RESOURCE': '#89c3eb',
|
|
27
|
+
'RESOURCE-SUBSET': '#a0d8ef',
|
|
28
|
+
'EVENT': '#f09199',
|
|
29
|
+
'EVENT-SUBSET': '#f6bfbc',
|
|
30
|
+
'COMPARATIVE': '#c8d5bb',
|
|
31
|
+
'CORRESPONDENCE': '#f2f2b0',
|
|
32
|
+
'RECURSION': '#dbd0e6',
|
|
33
|
+
'MANY-VALUED-OR': '#fddea5',
|
|
34
|
+
'MANY-VALUED-AND': '#9fd5c9',
|
|
35
|
+
'CLASS': '#bdc0ba',
|
|
36
|
+
};
|
|
37
|
+
/** 結線の中点から垂下(mapping)できる種別 */
|
|
38
|
+
export const MAPPING_TYPES = ['CORRESPONDENCE', 'COMPARATIVE', 'RECURSION'];
|
|
39
|
+
/** サブセット結線の区分コードの種類 */
|
|
40
|
+
export const SUBSET_KINDS = ['same', 'different'];
|
|
41
|
+
/** カーディナリティ(1 か 多) */
|
|
42
|
+
export const CARDINALITIES = [1, 3];
|
|
43
|
+
/** オプショナリティ(0 は任意、1 は必須) */
|
|
44
|
+
export const OPTIONALITIES = [0, 1];
|
|
45
|
+
/** エンティティの既定。size の 0 は「内容に合わせる」 */
|
|
46
|
+
export const ENTITY_DEFAULTS = {
|
|
47
|
+
position: { x: 0, y: 0 },
|
|
48
|
+
size: { w: 0, h: 0 },
|
|
49
|
+
};
|
|
50
|
+
/** 関係の既定。端点の角度は 0(真下)。cardinality / optionality は既定なし(無ければ記号を描かない) */
|
|
51
|
+
export const RELATIONSHIP_DEFAULTS = {
|
|
52
|
+
end: { position: 0 },
|
|
53
|
+
};
|
|
54
|
+
/** 種別として正しいか */
|
|
55
|
+
export function isEntityType(value) {
|
|
56
|
+
return typeof value === 'string' && ENTITY_TYPES.includes(value);
|
|
57
|
+
}
|
|
58
|
+
/** 関係か(from と to がエンティティを指す) */
|
|
59
|
+
export function isRelationship(record) {
|
|
60
|
+
const r = record;
|
|
61
|
+
return !!(r && r.from && typeof r.from === 'object' && 'entity' in r.from
|
|
62
|
+
&& r.to && typeof r.to === 'object' && 'entity' in r.to);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* エンティティか。関係でなく、type・インスタンスの配列・位置・大きさのどれかを持つ。
|
|
66
|
+
* マスタ(id と name だけ)と区別するための判定なので、id と name しか無いエンティティは見分けられない
|
|
67
|
+
* (entities[] の要素と分かっているときは entityWithDefaults を使う)。
|
|
68
|
+
*/
|
|
69
|
+
export function isEntity(record) {
|
|
70
|
+
if (!record || isRelationship(record))
|
|
71
|
+
return false;
|
|
72
|
+
const e = record;
|
|
73
|
+
return typeof e.type === 'string' || Array.isArray(e.identifiers) || Array.isArray(e.attributes)
|
|
74
|
+
|| e.position !== undefined || e.size !== undefined;
|
|
75
|
+
}
|
|
76
|
+
/** レコードの種類 */
|
|
77
|
+
export function kindOf(record) {
|
|
78
|
+
if (isRelationship(record))
|
|
79
|
+
return 'relationship';
|
|
80
|
+
return isEntity(record) ? 'entity' : 'master';
|
|
81
|
+
}
|
|
82
|
+
/** 表示する名前。文字列ならそのまま、Name なら logical(無ければ physical)。無ければ '' */
|
|
83
|
+
export function nameOf(record) {
|
|
84
|
+
const name = record.name;
|
|
85
|
+
if (typeof name === 'string')
|
|
86
|
+
return name;
|
|
87
|
+
if (name && typeof name === 'object')
|
|
88
|
+
return name.logical || name.physical || '';
|
|
89
|
+
return '';
|
|
90
|
+
}
|
|
91
|
+
/** 端点に既定を重ねる(角度が無ければ 0。cardinality / optionality は不正値なら除く) */
|
|
92
|
+
export function endWithDefaults(end) {
|
|
93
|
+
const out = {
|
|
94
|
+
...end,
|
|
95
|
+
position: typeof end.position === 'number' && Number.isFinite(end.position) ? end.position : RELATIONSHIP_DEFAULTS.end.position,
|
|
96
|
+
};
|
|
97
|
+
if (!CARDINALITIES.includes(end.cardinality))
|
|
98
|
+
delete out.cardinality;
|
|
99
|
+
if (!OPTIONALITIES.includes(end.optionality))
|
|
100
|
+
delete out.optionality;
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
/** 関係に既定を重ねる: from / to の position */
|
|
104
|
+
export function relationshipWithDefaults(record) {
|
|
105
|
+
return {
|
|
106
|
+
...record,
|
|
107
|
+
from: endWithDefaults(record.from),
|
|
108
|
+
to: endWithDefaults(record.to),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* エンティティに既定を重ねる: position(無ければ 0, 0)、size(無ければ 0, 0 = 内容に合わせる)。
|
|
113
|
+
* type は補わない(無ければ無いまま。d3.ter は描けないので check で知らせる)。
|
|
114
|
+
*/
|
|
115
|
+
export function entityWithDefaults(record) {
|
|
116
|
+
return {
|
|
117
|
+
...record,
|
|
118
|
+
position: { ...ENTITY_DEFAULTS.position, ...(record.position || {}) },
|
|
119
|
+
size: { ...ENTITY_DEFAULTS.size, ...(record.size || {}) },
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* レコードに、view が既定で使う値を重ねて返す(入力は書き換えない)。インスペクタの初期値に使う。
|
|
124
|
+
* 形から種類を決める(kindOf)。マスタはそのまま(複製だけ)。
|
|
125
|
+
* name は文字列か Name かを保つ(どちらで書いたかで編集できる項目が変わる — fieldsOf)。
|
|
126
|
+
*/
|
|
127
|
+
export function withDefaults(record) {
|
|
128
|
+
if (isRelationship(record))
|
|
129
|
+
return relationshipWithDefaults(record);
|
|
130
|
+
if (isEntity(record))
|
|
131
|
+
return entityWithDefaults(record);
|
|
132
|
+
return { ...record };
|
|
133
|
+
}
|
package/dist/fields.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TmCollection, TmField, TmRecord } from './types.js';
|
|
2
|
+
/** 名前の項目。name が Name(オブジェクト)なら論理名・物理名の 2 項目、それ以外は名称 1 項目 */
|
|
3
|
+
export declare function nameFields(record: TmRecord): TmField[];
|
|
4
|
+
/** エンティティの項目(名前のあと) */
|
|
5
|
+
export declare const ENTITY_FIELDS: readonly TmField[];
|
|
6
|
+
/**
|
|
7
|
+
* 関係の項目。接続位置はエンティティの中心から見た角度(0=真下・時計回り。90=左 / 180=真上 / 270=右)。
|
|
8
|
+
* カーディナリティ・オプショナリティは空にできる(記号を描かない)。
|
|
9
|
+
*/
|
|
10
|
+
export declare const RELATIONSHIP_FIELDS: readonly TmField[];
|
|
11
|
+
/** マスタ(識別子・属性)の項目(名前のあと) */
|
|
12
|
+
export declare const MASTER_FIELDS: readonly TmField[];
|
|
13
|
+
/**
|
|
14
|
+
* レコードに応じた項目の一覧。
|
|
15
|
+
* マスタは identifiers / attributes のどちらかをレコードの形から判別できないので、利用側が collection を渡す
|
|
16
|
+
* (項目は同じなので、渡さなくても一覧は変わらない。applyPatch では必須)。
|
|
17
|
+
*/
|
|
18
|
+
export declare function fieldsOf(record: TmRecord, _collection?: TmCollection): TmField[];
|
|
19
|
+
//# sourceMappingURL=fields.d.ts.map
|