@tasenor/common-node 1.9.84 → 1.9.86

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 @@
1
+ export * from './utils';
@@ -0,0 +1,2 @@
1
+ export * from './utils';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/data/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA"}
@@ -0,0 +1,156 @@
1
+ declare function setDir(dir: string): void;
2
+ /**
3
+ * Read in text from UTF-8 encoded file.
4
+ * @param fileName
5
+ */
6
+ declare function readFile(fileName: string): string;
7
+ /**
8
+ * Read TSV file so that first line defines names for columns, which are used in the mapping.
9
+ * @param file
10
+ * @param raw
11
+ * @returns
12
+ */
13
+ declare function readTsv(fileName: string, raw?: boolean): Record<string, string>[] | string[][];
14
+ /**
15
+ * Go through data entries and add `level` and `parent` fields. Remove _ prefixes from idField.
16
+ * @param data
17
+ * @param idField
18
+ */
19
+ declare function collectParents(data: any, idField: any): any;
20
+ /**
21
+ * Collect language codes from header line.
22
+ * @param data
23
+ */
24
+ declare function languages(data: any): string[];
25
+ /**
26
+ * Construct a language translation table.
27
+ * @param data
28
+ * @param prefix
29
+ * @param translations
30
+ */
31
+ declare function makeTranslations(data: any, prefix: any, translations: any): {};
32
+ /**
33
+ * Drop first and last bracket and add indentation to every line.
34
+ * @param output
35
+ */
36
+ declare function trimIndentation(output: any, indent?: string): string;
37
+ /**
38
+ * Load and pre-process a TSV file.
39
+ * @param fileName
40
+ */
41
+ declare function parseFile(fileName: any): any;
42
+ /**
43
+ * Refresh plugin translation data.
44
+ * @param prefix
45
+ * @param fileName
46
+ */
47
+ declare function rebuildTranslations(plugin: any, prefix: any, fileName: any): {};
48
+ /**
49
+ * Put together multiple translations and sort them all.
50
+ * @param files
51
+ * @returns
52
+ */
53
+ declare function combine(...files: any[]): {};
54
+ /**
55
+ * Do rude lint fixing for JSON string.
56
+ * @param text
57
+ */
58
+ declare function lint(text: any): any;
59
+ /**
60
+ * Insert text between the given separators in a file.
61
+ * @param pathParts
62
+ * @param text
63
+ * @param startSep
64
+ * @param endSep
65
+ */
66
+ declare function insertToFile(pathParts: any, text: any, startSep: any, endSep: any): void;
67
+ /**
68
+ * Construct actual data to store as a knowledge.
69
+ */
70
+ declare function buildData(data: any): {
71
+ root: null;
72
+ children: {};
73
+ parents: {};
74
+ };
75
+ /**
76
+ * Save JSON data to the plugin directory.
77
+ * @param name
78
+ * @param data
79
+ */
80
+ declare function saveJson(plugin: any, name: any, data: any): void;
81
+ /**
82
+ * Save text file as it is to the plugin directory.
83
+ * @param name
84
+ * @param data
85
+ */
86
+ declare function saveText(plugin: any, name: any, text: any): void;
87
+ /**
88
+ * Save text data to the file.
89
+ * @param plugin
90
+ * @param filePath
91
+ * @param text
92
+ */
93
+ declare function saveFile(plugin: any, filePath: any, text: any): void;
94
+ /**
95
+ * Remove _ prefixes from ID field.
96
+ * @param data
97
+ */
98
+ declare function trimId(value: any): any;
99
+ /**
100
+ * Remove _ prefixes from ID fields from each line.
101
+ * @param data
102
+ */
103
+ declare function trimIds(data: any, idField?: string): any;
104
+ /**
105
+ * Strip extras away and convert numeric string to proper number.
106
+ * @param data
107
+ */
108
+ declare function fixNumber(data: any): number;
109
+ /**
110
+ * Strip extras away and convert numeric string to proper number.
111
+ * @param data
112
+ * @param fieldName
113
+ */
114
+ declare function fixNumbers(data: any, fieldName: any): any;
115
+ /**
116
+ * Gather two values from data to form a mapping from one field value to another.
117
+ * @param data
118
+ * @param keyName
119
+ * @param valueName
120
+ */
121
+ declare function toMap(data: any, keyName: any, valueName: any): any;
122
+ /**
123
+ * Replace CRLF with LF.
124
+ * @param text
125
+ */
126
+ declare function trimCRLF(text: any): any;
127
+ /**
128
+ * Remove duplicated flags from report as TSV data.
129
+ */
130
+ declare function cleanFlagDuplicates(tsv: any): any;
131
+ export declare const dataUtils: {
132
+ buildData: typeof buildData;
133
+ cleanFlagDuplicates: typeof cleanFlagDuplicates;
134
+ collectParents: typeof collectParents;
135
+ combine: typeof combine;
136
+ fixNumber: typeof fixNumber;
137
+ fixNumbers: typeof fixNumbers;
138
+ insertToFile: typeof insertToFile;
139
+ languages: typeof languages;
140
+ lint: typeof lint;
141
+ makeTranslations: typeof makeTranslations;
142
+ parseFile: typeof parseFile;
143
+ readFile: typeof readFile;
144
+ readTsv: typeof readTsv;
145
+ rebuildTranslations: typeof rebuildTranslations;
146
+ saveFile: typeof saveFile;
147
+ saveJson: typeof saveJson;
148
+ saveText: typeof saveText;
149
+ setDir: typeof setDir;
150
+ toMap: typeof toMap;
151
+ trimCRLF: typeof trimCRLF;
152
+ trimId: typeof trimId;
153
+ trimIds: typeof trimIds;
154
+ trimIndentation: typeof trimIndentation;
155
+ };
156
+ export {};
@@ -0,0 +1,318 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { MAX_TARGET_ID_LEN } from '@tasenor/common';
4
+ let DIRNAME = '';
5
+ function setDir(dir) {
6
+ DIRNAME = dir;
7
+ }
8
+ /**
9
+ * Read in text from UTF-8 encoded file.
10
+ * @param fileName
11
+ */
12
+ function readFile(fileName) {
13
+ const file = path.join(DIRNAME, 'data', 'src', fileName);
14
+ const text = fs.readFileSync(file).toString('utf-8');
15
+ return text;
16
+ }
17
+ /**
18
+ * Read TSV file so that first line defines names for columns, which are used in the mapping.
19
+ * @param file
20
+ * @param raw
21
+ * @returns
22
+ */
23
+ function readTsv(fileName, raw = false) {
24
+ const data = readFile(fileName).split('\n').map(s => s.trim()).filter(s => !!s).map(s => s.split('\t'));
25
+ if (raw) {
26
+ return data;
27
+ }
28
+ const headers = data[0];
29
+ headers[0] = headers[0].replace(/^#\s*/, '');
30
+ const results = [];
31
+ for (let i = 1; i < data.length; i++) {
32
+ const item = {};
33
+ for (let j = 0; j < headers.length; j++) {
34
+ item[headers[j]] = data[i][j];
35
+ }
36
+ results.push(item);
37
+ }
38
+ return results;
39
+ }
40
+ /**
41
+ * Go through data entries and add `level` and `parent` fields. Remove _ prefixes from idField.
42
+ * @param data
43
+ * @param idField
44
+ */
45
+ function collectParents(data, idField) {
46
+ const parents = {
47
+ '-1': null,
48
+ 0: null,
49
+ 1: null,
50
+ 2: null,
51
+ 3: null,
52
+ 4: null,
53
+ 5: null,
54
+ 6: null
55
+ };
56
+ for (const line of data) {
57
+ const match = /^(_*)/.exec(line[idField]);
58
+ line.level = match && match[1].length;
59
+ line[idField] = line[idField].replace(/^_+/, '');
60
+ line.parent = parents[line.level - 1];
61
+ if (line.level && !line.parent) {
62
+ throw new Error(`Something wrong with ${JSON.stringify(line)}. Cannot find parent level for it.`);
63
+ }
64
+ parents[line.level] = line[idField];
65
+ }
66
+ return data;
67
+ }
68
+ /**
69
+ * Collect language codes from header line.
70
+ * @param data
71
+ */
72
+ function languages(data) {
73
+ return Object.keys(data[0]).slice(1).filter(k => /^[a-z][a-z]$/.test(k));
74
+ }
75
+ /**
76
+ * Construct a language translation table.
77
+ * @param data
78
+ * @param prefix
79
+ * @param translations
80
+ */
81
+ function makeTranslations(data, prefix, translations) {
82
+ const tr = {};
83
+ for (const lang of translations) {
84
+ tr[lang] = data.reduce((prev, cur) => ({ ...prev, [`${prefix}-${cur.id}`]: cur[lang] }), {});
85
+ }
86
+ return tr;
87
+ }
88
+ /**
89
+ * Drop first and last bracket and add indentation to every line.
90
+ * @param output
91
+ */
92
+ function trimIndentation(output, indent = '') {
93
+ let text = JSON.stringify(output, null, 2);
94
+ text = text.substr(2, text.length - 4);
95
+ const texts = text.split('\n').map(line => indent + line.replace(/^ {2}/, ''));
96
+ return '\n' + texts.join('\n') + '\n';
97
+ }
98
+ /**
99
+ * Load and pre-process a TSV file.
100
+ * @param fileName
101
+ */
102
+ function parseFile(fileName) {
103
+ const tsv = readTsv(fileName);
104
+ const data = collectParents(tsv, 'id');
105
+ return data;
106
+ }
107
+ /**
108
+ * Refresh plugin translation data.
109
+ * @param prefix
110
+ * @param fileName
111
+ */
112
+ function rebuildTranslations(plugin, prefix, fileName) {
113
+ const data = parseFile(fileName);
114
+ const translations = languages(data);
115
+ const output = makeTranslations(data, prefix, translations);
116
+ return output;
117
+ }
118
+ /**
119
+ * Put together multiple translations and sort them all.
120
+ * @param files
121
+ * @returns
122
+ */
123
+ function combine(...files) {
124
+ const all = {};
125
+ const languages = new Set();
126
+ for (const file of files) {
127
+ Object.entries(file).forEach(([lang, data]) => {
128
+ all[lang] = all[lang] || {};
129
+ languages.add(lang);
130
+ Object.assign(all[lang], data);
131
+ });
132
+ }
133
+ const sorted = {};
134
+ for (const lang of languages) {
135
+ sorted[lang] = {};
136
+ const keys = Object.keys(all[lang]).sort();
137
+ for (const k of keys) {
138
+ sorted[lang][k] = all[lang][k];
139
+ }
140
+ }
141
+ return sorted;
142
+ }
143
+ /**
144
+ * Do rude lint fixing for JSON string.
145
+ * @param text
146
+ */
147
+ function lint(text) {
148
+ return text.replace(/"/g, "'").replace(/'(\w+)':/g, '$1:');
149
+ }
150
+ /**
151
+ * Insert text between the given separators in a file.
152
+ * @param pathParts
153
+ * @param text
154
+ * @param startSep
155
+ * @param endSep
156
+ */
157
+ function insertToFile(pathParts, text, startSep, endSep) {
158
+ const filePath = path.join(DIRNAME, 'src', ...pathParts);
159
+ const current = fs.readFileSync(filePath).toString('utf-8').split(startSep);
160
+ if (current.length !== 2) {
161
+ throw new Error(`Insertion to ${filePath} failed: start separator ${JSON.stringify(startSep)} not correct.`);
162
+ }
163
+ const tail = current[1].split(endSep);
164
+ if (tail.length !== 2) {
165
+ throw new Error(`Insertion to ${filePath} failed: end separator ${JSON.stringify(endSep)} not correct.`);
166
+ }
167
+ const combined = current[0] + startSep + text + endSep + tail[1];
168
+ fs.writeFileSync(filePath, combined);
169
+ console.log(new Date(), `Refreshed translation data in ${filePath}`);
170
+ }
171
+ /**
172
+ * Construct actual data to store as a knowledge.
173
+ */
174
+ function buildData(data) {
175
+ const result = {
176
+ root: null,
177
+ children: {},
178
+ parents: {}
179
+ };
180
+ for (let i = 0; i < data.length; i++) {
181
+ const { id, parent } = data[i];
182
+ if (id.length > MAX_TARGET_ID_LEN) {
183
+ throw new Error(`An ID '${id}' is too long (max. ${MAX_TARGET_ID_LEN}).`);
184
+ }
185
+ result.parents[id] = parent;
186
+ if (!parent) {
187
+ if (result.root !== null) {
188
+ throw new Error(`Found second root element ${JSON.stringify(data[i])}.`);
189
+ }
190
+ result.root = id;
191
+ continue;
192
+ }
193
+ result.children[parent] = result.children[parent] || [];
194
+ result.children[parent].push(id);
195
+ }
196
+ return result;
197
+ }
198
+ /**
199
+ * Save JSON data to the plugin directory.
200
+ * @param name
201
+ * @param data
202
+ */
203
+ function saveJson(plugin, name, data) {
204
+ const filePath = path.join(DIRNAME, 'src', plugin, 'backend', `${name}.json`);
205
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
206
+ console.log(new Date(), `Saved JSON data to ${filePath}`);
207
+ }
208
+ /**
209
+ * Save text file as it is to the plugin directory.
210
+ * @param name
211
+ * @param data
212
+ */
213
+ function saveText(plugin, name, text) {
214
+ const filePath = path.join(DIRNAME, 'src', plugin, 'backend', name);
215
+ fs.writeFileSync(filePath, text);
216
+ console.log(new Date(), `Saved text data to ${filePath}`);
217
+ }
218
+ /**
219
+ * Save text data to the file.
220
+ * @param plugin
221
+ * @param filePath
222
+ * @param text
223
+ */
224
+ function saveFile(plugin, filePath, text) {
225
+ let targetPath;
226
+ if (plugin[0] === '@') {
227
+ const project = plugin.substr(1);
228
+ if (!fs.existsSync(path.join(DIRNAME, '..', project))) {
229
+ throw new Error(`Cannot find other project ${project} to write file.`);
230
+ }
231
+ targetPath = path.join(DIRNAME, '..', plugin.substr(1), filePath);
232
+ }
233
+ else {
234
+ targetPath = path.join(DIRNAME, 'src', plugin, filePath);
235
+ }
236
+ fs.writeFileSync(targetPath, text);
237
+ console.log(new Date(), `Saved data to ${targetPath}`);
238
+ }
239
+ /**
240
+ * Remove _ prefixes from ID field.
241
+ * @param data
242
+ */
243
+ function trimId(value) {
244
+ return value.replace(/^_+/, '');
245
+ }
246
+ /**
247
+ * Remove _ prefixes from ID fields from each line.
248
+ * @param data
249
+ */
250
+ function trimIds(data, idField = 'id') {
251
+ return data.map(line => ({ ...line, [idField]: trimId(line.id) }));
252
+ }
253
+ /**
254
+ * Strip extras away and convert numeric string to proper number.
255
+ * @param data
256
+ */
257
+ function fixNumber(data) {
258
+ return parseFloat(data.replace(/[^0-9.]/g, ''));
259
+ }
260
+ /**
261
+ * Strip extras away and convert numeric string to proper number.
262
+ * @param data
263
+ * @param fieldName
264
+ */
265
+ function fixNumbers(data, fieldName) {
266
+ return data.map(line => ({ ...line, [fieldName]: fixNumber(line[fieldName]) }));
267
+ }
268
+ /**
269
+ * Gather two values from data to form a mapping from one field value to another.
270
+ * @param data
271
+ * @param keyName
272
+ * @param valueName
273
+ */
274
+ function toMap(data, keyName, valueName) {
275
+ return data.reduce((prev, cur) => ({ ...prev, [cur[keyName]]: cur[valueName] }), {});
276
+ }
277
+ /**
278
+ * Replace CRLF with LF.
279
+ * @param text
280
+ */
281
+ function trimCRLF(text) {
282
+ return text.replace(/\r\n/g, '\n');
283
+ }
284
+ /**
285
+ * Remove duplicated flags from report as TSV data.
286
+ */
287
+ function cleanFlagDuplicates(tsv) {
288
+ const rempoveDuplicates = (s) => {
289
+ return [...new Set(s.split(' '))].join(' ').trim();
290
+ };
291
+ return tsv.split('\n').map(line => line.split('\t')).map(([a, b, c]) => [a, b, rempoveDuplicates(c)]).map(a => a.join('\t')).join('\n');
292
+ }
293
+ export const dataUtils = {
294
+ buildData,
295
+ cleanFlagDuplicates,
296
+ collectParents,
297
+ combine,
298
+ fixNumber,
299
+ fixNumbers,
300
+ insertToFile,
301
+ languages,
302
+ lint,
303
+ makeTranslations,
304
+ parseFile,
305
+ readFile,
306
+ readTsv,
307
+ rebuildTranslations,
308
+ saveFile,
309
+ saveJson,
310
+ saveText,
311
+ setDir,
312
+ toMap,
313
+ trimCRLF,
314
+ trimId,
315
+ trimIds,
316
+ trimIndentation,
317
+ };
318
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/data/utils.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export * from './cli';
2
+ export * from './data';
2
3
  export * from './database';
3
4
  export * from './error';
4
5
  export * from './export';
package/dist/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './cli';
2
+ export * from './data';
2
3
  export * from './database';
3
4
  export * from './error';
4
5
  export * from './export';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAA;AACrB,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,OAAO,CAAA;AACrB,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAA;AACrB,cAAc,QAAQ,CAAA;AACtB,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,OAAO,CAAA;AACrB,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tasenor/common-node",
3
- "version": "1.9.84",
3
+ "version": "1.9.86",
4
4
  "description": "Common Node-parts of Tasenor project",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -36,7 +36,7 @@
36
36
  "sqlite3": "^5.1.6",
37
37
  "tar": "^6.1.15",
38
38
  "ts-opaque": "^3.0.1",
39
- "@tasenor/common": "1.9.84"
39
+ "@tasenor/common": "1.9.86"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@jest/globals": "^29.6.1",
@@ -46,7 +46,7 @@
46
46
  "ts-jest": "^29.1.1",
47
47
  "typescript": "^5.1.6",
48
48
  "eslint-config-tasenor": "0.0.0",
49
- "@tasenor/config": "1.9.83"
49
+ "@tasenor/config": "1.9.85"
50
50
  },
51
51
  "scripts": {
52
52
  "ci": "pnpm run lint && pnpm run test",
@@ -0,0 +1 @@
1
+ export * from './utils'
@@ -0,0 +1,343 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+ import { MAX_TARGET_ID_LEN } from '@tasenor/common'
4
+
5
+ let DIRNAME = ''
6
+
7
+ function setDir(dir: string) {
8
+ DIRNAME = dir
9
+ }
10
+
11
+ /**
12
+ * Read in text from UTF-8 encoded file.
13
+ * @param fileName
14
+ */
15
+ function readFile(fileName: string): string {
16
+ const file = path.join(DIRNAME, 'data', 'src', fileName)
17
+ const text = fs.readFileSync(file).toString('utf-8')
18
+ return text
19
+ }
20
+
21
+ /**
22
+ * Read TSV file so that first line defines names for columns, which are used in the mapping.
23
+ * @param file
24
+ * @param raw
25
+ * @returns
26
+ */
27
+ function readTsv(fileName: string, raw = false): Record<string, string>[] | string[][] {
28
+ const data = readFile(fileName).split('\n').map(s => s.trim()).filter(s => !!s).map(s => s.split('\t'))
29
+ if (raw) {
30
+ return data
31
+ }
32
+ const headers: string[] = data[0]
33
+ headers[0] = headers[0].replace(/^#\s*/, '')
34
+ const results: Record<string, string>[] = []
35
+ for (let i = 1; i < data.length; i++) {
36
+ const item: Record<string, string> = {}
37
+ for (let j = 0; j < headers.length; j++) {
38
+ item[headers[j]] = data[i][j]
39
+ }
40
+ results.push(item)
41
+ }
42
+ return results
43
+ }
44
+
45
+ /**
46
+ * Go through data entries and add `level` and `parent` fields. Remove _ prefixes from idField.
47
+ * @param data
48
+ * @param idField
49
+ */
50
+ function collectParents(data, idField) {
51
+ const parents = {
52
+ '-1': null,
53
+ 0: null,
54
+ 1: null,
55
+ 2: null,
56
+ 3: null,
57
+ 4: null,
58
+ 5: null,
59
+ 6: null
60
+ }
61
+ for (const line of data) {
62
+ const match = /^(_*)/.exec(line[idField])
63
+ line.level = match && match[1].length
64
+ line[idField] = line[idField].replace(/^_+/, '')
65
+ line.parent = parents[line.level - 1]
66
+ if (line.level && !line.parent) {
67
+ throw new Error(`Something wrong with ${JSON.stringify(line)}. Cannot find parent level for it.`)
68
+ }
69
+ parents[line.level] = line[idField]
70
+ }
71
+ return data
72
+ }
73
+
74
+ /**
75
+ * Collect language codes from header line.
76
+ * @param data
77
+ */
78
+ function languages(data) {
79
+ return Object.keys(data[0]).slice(1).filter(k => /^[a-z][a-z]$/.test(k))
80
+ }
81
+
82
+ /**
83
+ * Construct a language translation table.
84
+ * @param data
85
+ * @param prefix
86
+ * @param translations
87
+ */
88
+ function makeTranslations(data, prefix, translations) {
89
+ const tr = {}
90
+ for (const lang of translations) {
91
+ tr[lang] = data.reduce((prev, cur) => ({ ...prev, [`${prefix}-${cur.id}`]: cur[lang] }), {})
92
+ }
93
+ return tr
94
+ }
95
+
96
+ /**
97
+ * Drop first and last bracket and add indentation to every line.
98
+ * @param output
99
+ */
100
+ function trimIndentation(output, indent = '') {
101
+ let text = JSON.stringify(output, null, 2)
102
+ text = text.substr(2, text.length - 4)
103
+ const texts = text.split('\n').map(line => indent + line.replace(/^ {2}/, ''))
104
+ return '\n' + texts.join('\n') + '\n'
105
+ }
106
+
107
+ /**
108
+ * Load and pre-process a TSV file.
109
+ * @param fileName
110
+ */
111
+ function parseFile(fileName) {
112
+ const tsv = readTsv(fileName)
113
+ const data = collectParents(tsv, 'id')
114
+ return data
115
+ }
116
+
117
+ /**
118
+ * Refresh plugin translation data.
119
+ * @param prefix
120
+ * @param fileName
121
+ */
122
+ function rebuildTranslations(plugin, prefix, fileName) {
123
+ const data = parseFile(fileName)
124
+ const translations = languages(data)
125
+ const output = makeTranslations(data, prefix, translations)
126
+ return output
127
+ }
128
+
129
+ /**
130
+ * Put together multiple translations and sort them all.
131
+ * @param files
132
+ * @returns
133
+ */
134
+ function combine(...files) {
135
+ const all = {}
136
+ const languages: Set<string> = new Set()
137
+ for (const file of files) {
138
+ Object.entries(file).forEach(([lang, data]) => {
139
+ all[lang] = all[lang] || {}
140
+ languages.add(lang)
141
+ Object.assign(all[lang], data)
142
+ })
143
+ }
144
+
145
+ const sorted = {}
146
+ for (const lang of languages) {
147
+ sorted[lang] = {}
148
+ const keys = Object.keys(all[lang]).sort()
149
+ for (const k of keys) {
150
+ sorted[lang][k] = all[lang][k]
151
+ }
152
+ }
153
+
154
+ return sorted
155
+ }
156
+
157
+ /**
158
+ * Do rude lint fixing for JSON string.
159
+ * @param text
160
+ */
161
+ function lint(text) {
162
+ return text.replace(/"/g, "'").replace(/'(\w+)':/g, '$1:')
163
+ }
164
+
165
+ /**
166
+ * Insert text between the given separators in a file.
167
+ * @param pathParts
168
+ * @param text
169
+ * @param startSep
170
+ * @param endSep
171
+ */
172
+ function insertToFile(pathParts, text, startSep, endSep) {
173
+ const filePath = path.join(DIRNAME, 'src', ...pathParts)
174
+ const current = fs.readFileSync(filePath).toString('utf-8').split(startSep)
175
+ if (current.length !== 2) {
176
+ throw new Error(`Insertion to ${filePath} failed: start separator ${JSON.stringify(startSep)} not correct.`)
177
+ }
178
+ const tail = current[1].split(endSep)
179
+ if (tail.length !== 2) {
180
+ throw new Error(`Insertion to ${filePath} failed: end separator ${JSON.stringify(endSep)} not correct.`)
181
+ }
182
+ const combined = current[0] + startSep + text + endSep + tail[1]
183
+ fs.writeFileSync(filePath, combined)
184
+ console.log(new Date(), `Refreshed translation data in ${filePath}`)
185
+ }
186
+
187
+ /**
188
+ * Construct actual data to store as a knowledge.
189
+ */
190
+ function buildData(data) {
191
+ const result = {
192
+ root: null,
193
+ children: {},
194
+ parents: {}
195
+ }
196
+ for (let i = 0; i < data.length; i++) {
197
+ const { id, parent } = data[i]
198
+ if (id.length > MAX_TARGET_ID_LEN) {
199
+ throw new Error(`An ID '${id}' is too long (max. ${MAX_TARGET_ID_LEN}).`)
200
+ }
201
+ result.parents[id] = parent
202
+ if (!parent) {
203
+ if (result.root !== null) {
204
+ throw new Error(`Found second root element ${JSON.stringify(data[i])}.`)
205
+ }
206
+ result.root = id
207
+ continue
208
+ }
209
+ result.children[parent] = result.children[parent] || []
210
+ result.children[parent].push(id)
211
+ }
212
+ return result
213
+ }
214
+
215
+ /**
216
+ * Save JSON data to the plugin directory.
217
+ * @param name
218
+ * @param data
219
+ */
220
+ function saveJson(plugin, name, data) {
221
+ const filePath = path.join(DIRNAME, 'src', plugin, 'backend', `${name}.json`)
222
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n')
223
+ console.log(new Date(), `Saved JSON data to ${filePath}`)
224
+ }
225
+
226
+ /**
227
+ * Save text file as it is to the plugin directory.
228
+ * @param name
229
+ * @param data
230
+ */
231
+ function saveText(plugin, name, text) {
232
+ const filePath = path.join(DIRNAME, 'src', plugin, 'backend', name)
233
+ fs.writeFileSync(filePath, text)
234
+ console.log(new Date(), `Saved text data to ${filePath}`)
235
+ }
236
+
237
+ /**
238
+ * Save text data to the file.
239
+ * @param plugin
240
+ * @param filePath
241
+ * @param text
242
+ */
243
+ function saveFile(plugin, filePath, text) {
244
+ let targetPath
245
+ if (plugin[0] === '@') {
246
+ const project = plugin.substr(1)
247
+ if (!fs.existsSync(path.join(DIRNAME, '..', project))) {
248
+ throw new Error(`Cannot find other project ${project} to write file.`)
249
+ }
250
+ targetPath = path.join(DIRNAME, '..', plugin.substr(1), filePath)
251
+ } else {
252
+ targetPath = path.join(DIRNAME, 'src', plugin, filePath)
253
+ }
254
+ fs.writeFileSync(targetPath, text)
255
+ console.log(new Date(), `Saved data to ${targetPath}`)
256
+ }
257
+
258
+ /**
259
+ * Remove _ prefixes from ID field.
260
+ * @param data
261
+ */
262
+ function trimId(value) {
263
+ return value.replace(/^_+/, '')
264
+ }
265
+
266
+ /**
267
+ * Remove _ prefixes from ID fields from each line.
268
+ * @param data
269
+ */
270
+ function trimIds(data, idField = 'id') {
271
+ return data.map(line => ({ ...line, [idField]: trimId(line.id) }))
272
+ }
273
+
274
+ /**
275
+ * Strip extras away and convert numeric string to proper number.
276
+ * @param data
277
+ */
278
+ function fixNumber(data) {
279
+ return parseFloat(data.replace(/[^0-9.]/g, ''))
280
+ }
281
+
282
+ /**
283
+ * Strip extras away and convert numeric string to proper number.
284
+ * @param data
285
+ * @param fieldName
286
+ */
287
+ function fixNumbers(data, fieldName) {
288
+ return data.map(line => ({ ...line, [fieldName]: fixNumber(line[fieldName]) }))
289
+ }
290
+
291
+ /**
292
+ * Gather two values from data to form a mapping from one field value to another.
293
+ * @param data
294
+ * @param keyName
295
+ * @param valueName
296
+ */
297
+ function toMap(data, keyName, valueName) {
298
+ return data.reduce((prev, cur) => ({ ...prev, [cur[keyName]]: cur[valueName] }), {})
299
+ }
300
+
301
+ /**
302
+ * Replace CRLF with LF.
303
+ * @param text
304
+ */
305
+ function trimCRLF(text) {
306
+ return text.replace(/\r\n/g, '\n')
307
+ }
308
+
309
+ /**
310
+ * Remove duplicated flags from report as TSV data.
311
+ */
312
+ function cleanFlagDuplicates(tsv) {
313
+ const rempoveDuplicates = (s) => {
314
+ return [...new Set(s.split(' '))].join(' ').trim()
315
+ }
316
+ return tsv.split('\n').map(line => line.split('\t')).map(([a, b, c]) => [a, b, rempoveDuplicates(c)]).map(a => a.join('\t')).join('\n')
317
+ }
318
+
319
+ export const dataUtils = {
320
+ buildData,
321
+ cleanFlagDuplicates,
322
+ collectParents,
323
+ combine,
324
+ fixNumber,
325
+ fixNumbers,
326
+ insertToFile,
327
+ languages,
328
+ lint,
329
+ makeTranslations,
330
+ parseFile,
331
+ readFile,
332
+ readTsv,
333
+ rebuildTranslations,
334
+ saveFile,
335
+ saveJson,
336
+ saveText,
337
+ setDir,
338
+ toMap,
339
+ trimCRLF,
340
+ trimId,
341
+ trimIds,
342
+ trimIndentation,
343
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './cli'
2
+ export * from './data'
2
3
  export * from './database'
3
4
  export * from './error'
4
5
  export * from './export'