tycho-components 0.40.3 → 0.40.5
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.
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EdgeDefinition, NodeDefinition, Position } from 'cytoscape';
|
|
2
|
+
import { Conllu, ConlluToken, Struct } from '../../configs';
|
|
3
|
+
export type CytoscapeTree = {
|
|
4
|
+
nodes: NodeDefinition[];
|
|
5
|
+
edges: EdgeDefinition[];
|
|
6
|
+
pan?: Position;
|
|
7
|
+
};
|
|
8
|
+
declare const ConlluUtils: {
|
|
9
|
+
convertToSentence: (conllText: string) => Conllu;
|
|
10
|
+
convertToConllu: (conllu: Conllu) => string;
|
|
11
|
+
convertToCytoscape: (conllu: Conllu) => CytoscapeTree;
|
|
12
|
+
getAsText: (conllu: Conllu) => string;
|
|
13
|
+
convertStructToConllu: (struct: Struct) => Conllu;
|
|
14
|
+
extractConlluTokens: (conllText: string) => ConlluToken[];
|
|
15
|
+
isNotEmptyConllu: (conllu: Conllu) => boolean;
|
|
16
|
+
deleteToken: (conllu: Conllu, tokenIndex: number) => Conllu;
|
|
17
|
+
getConlluTranslationFromStruct: (struct: Struct | undefined, lang: string) => string;
|
|
18
|
+
};
|
|
19
|
+
export default ConlluUtils;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
const convertStructToConllu = (struct) => {
|
|
2
|
+
return {
|
|
3
|
+
uid: struct.uid,
|
|
4
|
+
page: struct.page,
|
|
5
|
+
tokens: struct.conllu || [],
|
|
6
|
+
attributes: struct.attributes || {},
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
const getAsText = (conllu) => {
|
|
10
|
+
let value = '';
|
|
11
|
+
conllu.tokens.forEach((token) => {
|
|
12
|
+
value += `${token.form} `;
|
|
13
|
+
});
|
|
14
|
+
return value.trim();
|
|
15
|
+
};
|
|
16
|
+
const convertToCytoscape = (conllu) => {
|
|
17
|
+
const tokens = conllu.tokens.filter((t) => t.id?.indexOf('-') === -1);
|
|
18
|
+
if (tokens.length === 0)
|
|
19
|
+
return { nodes: [], edges: [] };
|
|
20
|
+
const nodes = [];
|
|
21
|
+
const edges = [];
|
|
22
|
+
const uids = [uuid()];
|
|
23
|
+
nodes.push({
|
|
24
|
+
data: {
|
|
25
|
+
id: uids[0],
|
|
26
|
+
root: true,
|
|
27
|
+
token: {
|
|
28
|
+
id: 0,
|
|
29
|
+
form: 'root',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
for (const token of tokens) {
|
|
34
|
+
const thisUid = uuid();
|
|
35
|
+
uids.push(thisUid);
|
|
36
|
+
nodes.push({
|
|
37
|
+
data: {
|
|
38
|
+
id: thisUid,
|
|
39
|
+
token,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
for (const token of tokens) {
|
|
44
|
+
if (token.head !== null && token.deprel) {
|
|
45
|
+
edges.push({
|
|
46
|
+
data: {
|
|
47
|
+
id: uuid(),
|
|
48
|
+
label: token.deprel,
|
|
49
|
+
target: uids[parseInt(token.id)],
|
|
50
|
+
source: uids[parseInt(token.head)],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { nodes, edges };
|
|
56
|
+
};
|
|
57
|
+
const isNotEmptyConllu = (conllu) => {
|
|
58
|
+
return conllu && conllu.tokens.length > 0;
|
|
59
|
+
};
|
|
60
|
+
const convertToSentence = (conllText) => {
|
|
61
|
+
const lines = conllText.trim().split('\n');
|
|
62
|
+
const headerInfo = {};
|
|
63
|
+
const tokens = [];
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
if (line.startsWith('#')) {
|
|
66
|
+
const [key, value] = line.split('=');
|
|
67
|
+
if (value)
|
|
68
|
+
headerInfo[key.slice(2).trim()] = value.trim();
|
|
69
|
+
else
|
|
70
|
+
headerInfo[key.slice(2).trim()] = '';
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const fields = line.split('\t');
|
|
74
|
+
// check if id has '-', if positive this is a splitter
|
|
75
|
+
if (fields[0].indexOf('-') != -1)
|
|
76
|
+
continue;
|
|
77
|
+
const token = {
|
|
78
|
+
id: fields[0],
|
|
79
|
+
form: fields[1],
|
|
80
|
+
lemma: fields[2],
|
|
81
|
+
upos: fields[3],
|
|
82
|
+
xpos: fields[4] !== '_' ? fields[4] : '',
|
|
83
|
+
feats: fields[5] !== '_' ? fields[5] : '',
|
|
84
|
+
head: fields[6] ? fields[6] : '',
|
|
85
|
+
deprel: fields[7] ? fields[7] : '',
|
|
86
|
+
deps: fields[8] !== '_' ? fields[8] : '',
|
|
87
|
+
misc: fields[9] !== '_' ? fields[9] : '',
|
|
88
|
+
};
|
|
89
|
+
tokens.push(token);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const conllu = {
|
|
93
|
+
uid: uuid(),
|
|
94
|
+
page: '',
|
|
95
|
+
attributes: headerInfo || {},
|
|
96
|
+
tokens: tokens,
|
|
97
|
+
};
|
|
98
|
+
return conllu;
|
|
99
|
+
};
|
|
100
|
+
const convertToConllu = (conllu) => {
|
|
101
|
+
if (!isNotEmptyConllu(conllu))
|
|
102
|
+
return '';
|
|
103
|
+
const attributesLines = Object.entries(conllu.attributes)
|
|
104
|
+
.map(([key, value]) => `# ${key} = ${value}`)
|
|
105
|
+
.join('\n');
|
|
106
|
+
const tokenLines = conllu.tokens
|
|
107
|
+
.map((token) => [
|
|
108
|
+
token.id,
|
|
109
|
+
token.form,
|
|
110
|
+
token.lemma,
|
|
111
|
+
token.upos,
|
|
112
|
+
token.xpos,
|
|
113
|
+
token.feats,
|
|
114
|
+
token.head,
|
|
115
|
+
token.deprel,
|
|
116
|
+
token.deps === '' ? '_' : token.deps,
|
|
117
|
+
token.misc,
|
|
118
|
+
].join('\t'))
|
|
119
|
+
.join('\n');
|
|
120
|
+
return [attributesLines, tokenLines].join('\n');
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Deletes a token from the Conllu structure and updates all related references.
|
|
124
|
+
* - Updates token IDs to maintain sequential order (1, 2, 3, ...)
|
|
125
|
+
* - Updates HEAD references: if HEAD points to deleted token, points to previous token (or first if deleted was first)
|
|
126
|
+
* - Decrements HEAD references that point to tokens after the deleted one
|
|
127
|
+
*/
|
|
128
|
+
const deleteToken = (conllu, tokenIndex) => {
|
|
129
|
+
if (tokenIndex < 0 || tokenIndex >= conllu.tokens.length) {
|
|
130
|
+
return conllu;
|
|
131
|
+
}
|
|
132
|
+
// Get the ID of the token being deleted (as number for comparison)
|
|
133
|
+
const deletedToken = conllu.tokens[tokenIndex];
|
|
134
|
+
const deletedTokenId = deletedToken.id;
|
|
135
|
+
const deletedTokenIdNum = Number(deletedTokenId);
|
|
136
|
+
// Calculate the new ID of the token before the deleted one
|
|
137
|
+
// After deletion and renumbering, if we delete at index i:
|
|
138
|
+
// - Token at index i-1 will have new ID = i (which is String(i))
|
|
139
|
+
// - If deleting first token (index 0), the new first token will have ID "1"
|
|
140
|
+
const previousTokenNewId = tokenIndex > 0 ? String(tokenIndex) : conllu.tokens.length > 1 ? '1' : '0';
|
|
141
|
+
// Remove the token at the specified index
|
|
142
|
+
const updatedTokens = conllu.tokens.filter((_, index) => index !== tokenIndex);
|
|
143
|
+
// Update IDs to be sequential (1, 2, 3, ...)
|
|
144
|
+
const tokensWithUpdatedIds = updatedTokens.map((token, index) => ({
|
|
145
|
+
...token,
|
|
146
|
+
id: String(index + 1),
|
|
147
|
+
}));
|
|
148
|
+
// Update HEAD references based on the old IDs before deletion
|
|
149
|
+
const tokensWithUpdatedHeads = tokensWithUpdatedIds.map((token, newIndex) => {
|
|
150
|
+
// Get the original token (before ID update) to check its original HEAD
|
|
151
|
+
const originalToken = updatedTokens[newIndex];
|
|
152
|
+
// Skip if HEAD is empty, null, or '_'
|
|
153
|
+
if (!originalToken.head ||
|
|
154
|
+
originalToken.head === '_' ||
|
|
155
|
+
originalToken.head === '') {
|
|
156
|
+
return token;
|
|
157
|
+
}
|
|
158
|
+
const headIdNum = Number(originalToken.head);
|
|
159
|
+
// If HEAD points to the deleted token, point to the previous token (or first if deleted was first)
|
|
160
|
+
if (originalToken.head === deletedTokenId) {
|
|
161
|
+
return {
|
|
162
|
+
...token,
|
|
163
|
+
head: previousTokenNewId,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// If HEAD points to a token after the deleted one, decrement it by 1
|
|
167
|
+
if (headIdNum > deletedTokenIdNum) {
|
|
168
|
+
return {
|
|
169
|
+
...token,
|
|
170
|
+
head: String(headIdNum - 1),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// If HEAD points to a token before the deleted one, no change needed
|
|
174
|
+
// But we need to ensure the HEAD value is still valid after renumbering
|
|
175
|
+
// Since tokens before the deleted one keep their relative positions, their IDs don't change
|
|
176
|
+
// So we can keep the original HEAD value
|
|
177
|
+
return token;
|
|
178
|
+
});
|
|
179
|
+
return {
|
|
180
|
+
...conllu,
|
|
181
|
+
tokens: tokensWithUpdatedHeads,
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
const uuid = () => 'xxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
185
|
+
/* eslint-disable */
|
|
186
|
+
const r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8;
|
|
187
|
+
/* eslint-enable */
|
|
188
|
+
return v.toString(16);
|
|
189
|
+
});
|
|
190
|
+
const extractConlluTokens = (conllText) => {
|
|
191
|
+
const lines = conllText.trim().split('\n');
|
|
192
|
+
const headerInfo = {};
|
|
193
|
+
const tokens = [];
|
|
194
|
+
for (const line of lines) {
|
|
195
|
+
if (line.startsWith('#')) {
|
|
196
|
+
const [key, value] = line.split('=');
|
|
197
|
+
if (value)
|
|
198
|
+
headerInfo[key.slice(2).trim()] = value.trim();
|
|
199
|
+
else
|
|
200
|
+
headerInfo[key.slice(2).trim()] = '';
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
const fields = line.split('\t');
|
|
204
|
+
// check if id has '-', if positive this is a splitter
|
|
205
|
+
if (fields[0].indexOf('-') != -1)
|
|
206
|
+
continue;
|
|
207
|
+
const token = {
|
|
208
|
+
id: fields[0],
|
|
209
|
+
form: fields[1],
|
|
210
|
+
lemma: fields[2],
|
|
211
|
+
upos: fields[3],
|
|
212
|
+
xpos: fields[4] !== '_' ? fields[4] : '',
|
|
213
|
+
feats: fields[5] !== '_' ? fields[5] : '',
|
|
214
|
+
head: fields[6] ? fields[6] : '',
|
|
215
|
+
deprel: fields[7] ? fields[7] : '',
|
|
216
|
+
deps: fields[8] !== '_' ? fields[8] : '',
|
|
217
|
+
misc: fields[9] !== '_' ? fields[9] : '',
|
|
218
|
+
};
|
|
219
|
+
tokens.push(token);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return tokens;
|
|
223
|
+
};
|
|
224
|
+
const getConlluTranslationFromStruct = (struct, lang) => {
|
|
225
|
+
return struct?.attributes?.[lang] || '';
|
|
226
|
+
};
|
|
227
|
+
const ConlluUtils = {
|
|
228
|
+
convertToSentence,
|
|
229
|
+
convertToConllu,
|
|
230
|
+
convertToCytoscape,
|
|
231
|
+
getAsText,
|
|
232
|
+
convertStructToConllu,
|
|
233
|
+
extractConlluTokens,
|
|
234
|
+
isNotEmptyConllu,
|
|
235
|
+
deleteToken,
|
|
236
|
+
getConlluTranslationFromStruct,
|
|
237
|
+
};
|
|
238
|
+
export default ConlluUtils;
|
|
@@ -8,7 +8,8 @@ export { default as SentenceUtils } from './SentenceUtils';
|
|
|
8
8
|
export { EDITION_TOOLS, default as ToolsUtils, type PlatformTools, } from './ToolsUtils';
|
|
9
9
|
export type { OpenDocumentParams, RedirectPageParams } from './ToolsUtils';
|
|
10
10
|
export { default as UsabilityUtils } from './UsabilityUtils';
|
|
11
|
-
export { conlluViewerConfigurations
|
|
12
|
-
export { default as
|
|
11
|
+
export { conlluViewerConfigurations } from './conllu/ConlluViewerConstants';
|
|
12
|
+
export { default as ConlluUtils } from './conllu/ConlluUtils';
|
|
13
|
+
export { default as ConlluViewerConverter, calculateConlluTextWidth, throwConlluError, } from './conllu/ConlluViewerConverter';
|
|
13
14
|
export type { ConlluViewerAnchor, ConlluViewerDependency, ConlluViewerGraph, ConlluViewerItem, ConlluViewerMulti, } from './conllu/ConlluViewerGraph';
|
|
14
15
|
export { normalizeCorpusFromApi } from './normalizeCorpusFromApi';
|
package/dist/functions/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export { default as SecurityUtils } from './SecurityUtils';
|
|
|
7
7
|
export { default as SentenceUtils } from './SentenceUtils';
|
|
8
8
|
export { EDITION_TOOLS, default as ToolsUtils, } from './ToolsUtils';
|
|
9
9
|
export { default as UsabilityUtils } from './UsabilityUtils';
|
|
10
|
-
export { conlluViewerConfigurations
|
|
11
|
-
export { default as
|
|
10
|
+
export { conlluViewerConfigurations } from './conllu/ConlluViewerConstants';
|
|
11
|
+
export { default as ConlluUtils } from './conllu/ConlluUtils';
|
|
12
|
+
export { default as ConlluViewerConverter, calculateConlluTextWidth, throwConlluError, } from './conllu/ConlluViewerConverter';
|
|
12
13
|
export { normalizeCorpusFromApi } from './normalizeCorpusFromApi';
|