@diplodoc/cli 4.13.6 → 4.13.7

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "author": "Yandex Data UI Team <data-ui@yandex-team.ru>",
4
4
  "description": "Make documentation using yfm-docs in Markdown and HTML formats",
5
5
  "license": "MIT",
6
- "version": "4.13.6",
6
+ "version": "4.13.7",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git@github.com:diplodoc-platform/cli.git"
@@ -33,10 +33,10 @@
33
33
  "@aws-sdk/client-s3": "^3.369.0",
34
34
  "@diplodoc/client": "^2.0.5",
35
35
  "@diplodoc/latex-extension": "^1.1.0",
36
- "@diplodoc/markdown-translation": "^2.0.0-beta-1",
37
36
  "@diplodoc/mermaid-extension": "^1.2.1",
38
37
  "@diplodoc/openapi-extension": "^1.4.13",
39
38
  "@diplodoc/transform": "^4.8.2",
39
+ "@diplodoc/translation": "^1.0.6",
40
40
  "@octokit/core": "4.2.4",
41
41
  "@yandex-cloud/nodejs-sdk": "^2.2.2",
42
42
  "ajv": "^8.11.0",
package/src/cmd/index.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export {build} from './build';
2
2
  export {publish} from './publish';
3
- export {xliff} from './xliff';
4
3
  export {translate} from './translate';
@@ -0,0 +1,123 @@
1
+ import {mkdir} from 'node:fs/promises';
2
+ import {dirname, extname, join} from 'path';
3
+ import {Arguments, Argv} from 'yargs';
4
+ import {eachLimit} from 'async';
5
+ import {ComposeOptions, compose as _compose} from '@diplodoc/translation';
6
+
7
+ import {ArgvService} from '../../services';
8
+ import {argvValidator} from '../../validator';
9
+ import {TranslateParams, dumpFile, loadFile, normalizeParams, resolveSchemas} from './utils';
10
+
11
+ const command = 'compose';
12
+
13
+ const description = 'compose xliff and skeleton into documentation';
14
+
15
+ const compose = {command, description, handler, builder};
16
+
17
+ const MAX_CONCURRENCY = 50;
18
+
19
+ function builder<T>(argv: Argv<T>) {
20
+ return argv
21
+ .option('input', {
22
+ alias: 'i',
23
+ describe: 'input folder with xliff and skeleton files',
24
+ type: 'string',
25
+ default: process.cwd(),
26
+ })
27
+ .option('output', {
28
+ alias: 'o',
29
+ describe: 'output folder where translated markdown will be stored',
30
+ type: 'string',
31
+ default: process.cwd(),
32
+ })
33
+ .option('use-source', {
34
+ describe: 'for debug',
35
+ type: 'boolean',
36
+ })
37
+ .check(argvValidator);
38
+ }
39
+
40
+ type InputParams = {
41
+ input: string;
42
+ output: string;
43
+ };
44
+
45
+ type HandlerParams = {
46
+ exclude?: string[];
47
+ useSource?: boolean;
48
+ translate?: HandlerParams & {
49
+ compose?: HandlerParams;
50
+ };
51
+ };
52
+
53
+ type FileInfo = {
54
+ path: string;
55
+ xliff: string;
56
+ skl: string;
57
+ ext: string;
58
+ };
59
+
60
+ async function handler(args: Arguments<InputParams & HandlerParams>) {
61
+ const params = normalizeParams(
62
+ {
63
+ ...(args.translate || {}),
64
+ ...(args.translate?.compose || {}),
65
+ ...args,
66
+ },
67
+ ['.skl', '.xliff'],
68
+ );
69
+
70
+ ArgvService.init(params);
71
+
72
+ const {
73
+ input,
74
+ output,
75
+ files,
76
+ useSource = false,
77
+ } = ArgvService.getConfig() as unknown as TranslateParams;
78
+
79
+ const pairs = files.reduce(
80
+ (acc, file) => {
81
+ const ext = extname(file);
82
+ const path = file.slice(0, -ext.length);
83
+
84
+ acc[path] = acc[path] || {path, ext};
85
+ acc[path][ext.slice(1) as 'xliff' | 'skl'] = file;
86
+
87
+ return acc;
88
+ },
89
+ {} as Record<string, FileInfo>,
90
+ );
91
+
92
+ const configuredPipeline = pipeline(input, output, {useSource});
93
+
94
+ await eachLimit(pairs, MAX_CONCURRENCY, configuredPipeline);
95
+ }
96
+
97
+ function pipeline(input: string, output: string, {useSource}: ComposeOptions) {
98
+ return async (file: FileInfo) => {
99
+ const [skeleton, xliff] = await Promise.all([
100
+ loadFile(join(input, file.skl)),
101
+ loadFile<string>(join(input, file.xliff)),
102
+ ]);
103
+
104
+ let schemas;
105
+ if (['.yaml', '.json'].includes(file.ext)) {
106
+ schemas = resolveSchemas(file.path);
107
+
108
+ if (!schemas) {
109
+ return;
110
+ }
111
+ }
112
+
113
+ const result = _compose(skeleton, xliff, {useSource, schemas});
114
+ const filePath = join(output, file.path);
115
+
116
+ await mkdir(dirname(filePath), {recursive: true});
117
+ await dumpFile(filePath, result);
118
+ };
119
+ }
120
+
121
+ export {compose};
122
+
123
+ export default {compose};
@@ -0,0 +1,149 @@
1
+ import {ok} from 'assert';
2
+ import {mkdir} from 'node:fs/promises';
3
+ import {dirname, extname, join, resolve} from 'path';
4
+ import {Arguments, Argv} from 'yargs';
5
+ import {asyncify, eachLimit} from 'async';
6
+ import {ExtractOptions, extract as _extract} from '@diplodoc/translation';
7
+
8
+ import {ArgvService} from '../../services';
9
+ import {argvValidator} from '../../validator';
10
+ import {TranslateParams, dumpFile, loadFile, normalizeParams, resolveSchemas} from './utils';
11
+
12
+ const command = 'extract';
13
+
14
+ const description = 'extract xliff and skeleton from yfm documentation';
15
+
16
+ const extract = {command, description, handler, builder};
17
+
18
+ const MAX_CONCURRENCY = 50;
19
+
20
+ function builder<T>(argv: Argv<T>) {
21
+ return argv
22
+ .option('input', {
23
+ alias: 'i',
24
+ describe: 'input folder with xliff and skeleton files',
25
+ type: 'string',
26
+ default: process.cwd(),
27
+ })
28
+ .option('output', {
29
+ alias: 'o',
30
+ describe: 'output folder where translated markdown will be stored',
31
+ type: 'string',
32
+ default: process.cwd(),
33
+ })
34
+ .option('source', {
35
+ alias: ['sll', 'source-language-locale'],
36
+ describe: 'source language and locale',
37
+ type: 'string',
38
+ })
39
+ .option('target', {
40
+ alias: ['tll', 'target-language-locale'],
41
+ describe: 'target language and locale',
42
+ type: 'string',
43
+ })
44
+ .check(argvValidator);
45
+ }
46
+
47
+ type InputParams = {
48
+ input: string;
49
+ output: string;
50
+ };
51
+
52
+ type HandlerParams = {
53
+ include?: string[];
54
+ exclude?: string[];
55
+ source?: string;
56
+ sourceLanguage?: string;
57
+ sourceLocale?: string;
58
+ sourceLanguageLocale?: string;
59
+ target?: string;
60
+ targetLanguage?: string;
61
+ targetLocale?: string;
62
+ targetLanguageLocale?: string;
63
+ translate?: HandlerParams & {
64
+ extract?: HandlerParams;
65
+ };
66
+ };
67
+
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ async function handler(args: Arguments<InputParams & HandlerParams>) {
70
+ const params = normalizeParams({
71
+ ...(args.translate || {}),
72
+ ...(args.translate?.extract || {}),
73
+ ...args,
74
+ });
75
+
76
+ ArgvService.init(params);
77
+
78
+ const {input, output, source, targets, files} =
79
+ ArgvService.getConfig() as unknown as TranslateParams;
80
+
81
+ ok(source, `Required param source is not configured`);
82
+ ok(targets.length, `Required param target is not configured`);
83
+
84
+ for (const target of targets) {
85
+ const [sourceLanguage, sourceLocale] = source;
86
+ const [targetLanguage, targetLocale] = target;
87
+
88
+ ok(sourceLanguage && sourceLocale, 'Invalid source language-locale config');
89
+ ok(targetLanguage && targetLocale, 'Invalid target language-locale config');
90
+
91
+ const configuredPipeline = pipeline({
92
+ source: {language: sourceLanguage, locale: sourceLocale},
93
+ target: {language: targetLanguage, locale: targetLocale},
94
+ input,
95
+ output,
96
+ });
97
+
98
+ await eachLimit(files, MAX_CONCURRENCY, asyncify(configuredPipeline));
99
+ }
100
+ }
101
+
102
+ export type PipelineParameters = {
103
+ input: string;
104
+ output: string;
105
+ source: ExtractOptions['source'];
106
+ target: ExtractOptions['target'];
107
+ };
108
+
109
+ function pipeline(params: PipelineParameters) {
110
+ const {input, output, source, target} = params;
111
+ const inputRoot = resolve(input);
112
+ const outputRoot = resolve(output);
113
+
114
+ return async (path: string) => {
115
+ const ext = extname(path);
116
+ if (!['.yaml', '.json', '.md'].includes(ext)) {
117
+ return;
118
+ }
119
+
120
+ const inputPath = join(inputRoot, path);
121
+ const outputPath = path.replace(source.language, target.language);
122
+ const xliffPath = join(outputRoot, outputPath + '.xliff');
123
+ const skeletonPath = join(outputRoot, outputPath + '.skl');
124
+
125
+ let schemas;
126
+ if (['.yaml', '.json'].includes(ext)) {
127
+ schemas = resolveSchemas(path);
128
+
129
+ if (!schemas) {
130
+ return;
131
+ }
132
+ }
133
+
134
+ const content = await loadFile(inputPath);
135
+
136
+ await mkdir(dirname(xliffPath), {recursive: true});
137
+
138
+ const {xliff, skeleton} = _extract(content, {
139
+ source,
140
+ target,
141
+ });
142
+
143
+ await Promise.all([dumpFile(skeletonPath, skeleton), dumpFile(xliffPath, xliff)]);
144
+ };
145
+ }
146
+
147
+ export {extract};
148
+
149
+ export default {extract};