@diplodoc/cli 4.13.6 → 4.13.8

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/build/index.js CHANGED
@@ -56,7 +56,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
56
56
  mod
57
57
  ));
58
58
  var __async = (__this, __arguments, generator) => {
59
- return new Promise((resolve19, reject) => {
59
+ return new Promise((resolve20, reject) => {
60
60
  var fulfilled = (value) => {
61
61
  try {
62
62
  step(generator.next(value));
@@ -71,7 +71,7 @@ var __async = (__this, __arguments, generator) => {
71
71
  reject(e);
72
72
  }
73
73
  };
74
- var step = (x) => x.done ? resolve19(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
74
+ var step = (x) => x.done ? resolve20(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
75
75
  step((generator = generator.apply(__this, __arguments)).next());
76
76
  });
77
77
  };
@@ -1878,10 +1878,10 @@ function filterFile(path) {
1878
1878
  resolveConditions: true
1879
1879
  });
1880
1880
  parsedIndex.title = liquidField(title, combinedVars, path);
1881
- const description6 = filterTextItems(parsedIndex.description, combinedVars, {
1881
+ const description5 = filterTextItems(parsedIndex.description, combinedVars, {
1882
1882
  resolveConditions: true
1883
1883
  });
1884
- parsedIndex.description = liquidFields(description6, combinedVars, path);
1884
+ parsedIndex.description = liquidFields(description5, combinedVars, path);
1885
1885
  if ((_a = parsedIndex.meta) == null ? void 0 : _a.title) {
1886
1886
  const metaTitle = firstFilterTextItems(parsedIndex.meta.title, combinedVars, {
1887
1887
  resolveConditions: true
@@ -3640,147 +3640,287 @@ function handler2(args) {
3640
3640
  });
3641
3641
  }
3642
3642
 
3643
- // src/cmd/xliff/extract.ts
3643
+ // src/cmd/translate/extract.ts
3644
+ var import_assert2 = require("assert");
3645
+ var import_promises4 = require("fs/promises");
3646
+ var import_path32 = require("path");
3647
+ var import_async3 = require("async");
3648
+ var import_translation3 = require("@diplodoc/translation");
3649
+
3650
+ // src/cmd/translate/utils/index.ts
3644
3651
  var import_assert = require("assert");
3652
+ var import_path31 = require("path");
3653
+ var import_node_fs = require("fs");
3645
3654
  var import_glob4 = __toESM(require("glob"));
3655
+
3656
+ // src/cmd/translate/utils/fs.ts
3657
+ var import_translation = require("@diplodoc/translation");
3646
3658
  var import_path30 = require("path");
3647
- var import_markdown_translation = require("@diplodoc/markdown-translation");
3648
- var import_async3 = require("async");
3649
- var {
3650
- promises: { readFile: readFile3, writeFile: writeFile2, mkdir: mkdir2 }
3651
- } = require("fs");
3659
+ var import_js_yaml9 = require("js-yaml");
3660
+ var import_promises3 = require("fs/promises");
3661
+ function parseFile(text, path) {
3662
+ if (typeof text !== "string") {
3663
+ return text;
3664
+ }
3665
+ switch ((0, import_path30.extname)(path)) {
3666
+ case ".yaml":
3667
+ return (0, import_js_yaml9.load)(text);
3668
+ case ".json":
3669
+ return JSON.parse(text);
3670
+ default:
3671
+ return text;
3672
+ }
3673
+ }
3674
+ function stringifyFile(content, path) {
3675
+ if (typeof content === "string") {
3676
+ return content;
3677
+ }
3678
+ switch ((0, import_path30.extname)(path)) {
3679
+ case ".yaml":
3680
+ return (0, import_js_yaml9.dump)(content);
3681
+ case ".json":
3682
+ return JSON.stringify(content);
3683
+ default:
3684
+ return content;
3685
+ }
3686
+ }
3687
+ function loadFile(path) {
3688
+ return __async(this, null, function* () {
3689
+ const text = yield (0, import_promises3.readFile)(path, "utf8");
3690
+ let content = parseFile(text, path);
3691
+ if (content && typeof content === "object") {
3692
+ content = yield (0, import_translation.resolveRefs)(content, path, parseFile);
3693
+ }
3694
+ return content;
3695
+ });
3696
+ }
3697
+ function dumpFile(path, content) {
3698
+ return __async(this, null, function* () {
3699
+ const text = stringifyFile(content, path);
3700
+ yield (0, import_promises3.writeFile)(path, text, "utf8");
3701
+ });
3702
+ }
3703
+
3704
+ // src/cmd/translate/utils/translate.ts
3705
+ var import_translation2 = require("@diplodoc/translation");
3706
+ var ExtractError = class extends Error {
3707
+ constructor(error) {
3708
+ super((error == null ? void 0 : error.message) || String(error));
3709
+ this.code = "EXTRACT_ERROR";
3710
+ }
3711
+ };
3712
+ var ComposeError = class extends Error {
3713
+ constructor(error) {
3714
+ super((error == null ? void 0 : error.message) || String(error));
3715
+ this.code = "COMPOSE_ERROR";
3716
+ }
3717
+ };
3718
+ function extract2(content, options) {
3719
+ try {
3720
+ const { units, skeleton } = (0, import_translation2.extract)(content, options);
3721
+ return { units, skeleton };
3722
+ } catch (error) {
3723
+ throw new ExtractError(error);
3724
+ }
3725
+ }
3726
+ function compose(skeleton, xliff, options) {
3727
+ try {
3728
+ return (0, import_translation2.compose)(skeleton, xliff, options);
3729
+ } catch (error) {
3730
+ throw new ComposeError(error);
3731
+ }
3732
+ }
3733
+
3734
+ // src/cmd/translate/utils/index.ts
3735
+ function normalizeParams(params, exts = EXTS) {
3736
+ const source = normalizeLocale(params, "source")[0];
3737
+ const targets = normalizeLocale(params, "target");
3738
+ const { input, files } = normalizeInput(params, source[0], exts);
3739
+ const { output, auth, folder, dryRun, useSource } = params;
3740
+ (0, import_assert.ok)(input, "Required param input is not configured");
3741
+ return {
3742
+ input,
3743
+ output: output || input,
3744
+ auth,
3745
+ folder,
3746
+ source,
3747
+ targets,
3748
+ files: [...new Set(files)],
3749
+ dryRun: Boolean(dryRun),
3750
+ useSource: Boolean(useSource)
3751
+ };
3752
+ }
3753
+ function normalizeLocale(params, scope) {
3754
+ const _scopeLanguage = params[scope + "Language"];
3755
+ const _scopeLanguageLocale = params[scope + "LanguageLocale"];
3756
+ const _scope = params[scope] || _scopeLanguageLocale || _scopeLanguage;
3757
+ if (!_scope) {
3758
+ return [["", ""]];
3759
+ }
3760
+ if (Array.isArray(_scope)) {
3761
+ return _scope.map((_scope2) => _scope2.split("-"));
3762
+ }
3763
+ return [_scope.split("-")];
3764
+ }
3765
+ var EXTS = [".md", ".yaml", ".json"];
3766
+ function normalizeInput(params, language, exts) {
3767
+ let { input, include = [], exclude = [] } = params;
3768
+ include = [].concat(include);
3769
+ exclude = [].concat(exclude);
3770
+ let files = null;
3771
+ if ((0, import_path31.extname)(input) === ".list") {
3772
+ const list = (0, import_node_fs.readFileSync)(input, "utf8").split("\n");
3773
+ input = (0, import_path31.dirname)(input);
3774
+ files = list.map((file) => {
3775
+ const absPath = (0, import_path31.resolve)(input, file);
3776
+ if (!absPath.startsWith(input)) {
3777
+ throw new Error(`Insecure access to file out of project scope. (file: ${absPath})`);
3778
+ }
3779
+ if (!exts.includes((0, import_path31.extname)(file))) {
3780
+ throw new Error(`Unhandles file extension. (file: ${absPath})`);
3781
+ }
3782
+ return absPath;
3783
+ });
3784
+ } else {
3785
+ if (exts.includes((0, import_path31.extname)(input))) {
3786
+ files = [(0, import_path31.basename)(input)];
3787
+ input = (0, import_path31.dirname)(input);
3788
+ }
3789
+ if (!include.length) {
3790
+ include.push("...");
3791
+ }
3792
+ include = include.reduce((acc, item) => {
3793
+ if (item === "...") {
3794
+ acc.push(...exts.map((ext) => (language || ".") + "/**/*" + ext));
3795
+ } else {
3796
+ acc.push(item);
3797
+ }
3798
+ return acc;
3799
+ }, []);
3800
+ files = files || [].concat(
3801
+ ...include.map(
3802
+ (match) => import_glob4.default.sync(match, {
3803
+ cwd: input,
3804
+ ignore: exclude,
3805
+ nodir: true
3806
+ })
3807
+ )
3808
+ );
3809
+ }
3810
+ return { input, files };
3811
+ }
3812
+ function resolveSchemas(_path) {
3813
+ return null;
3814
+ }
3815
+ var Defer = class {
3816
+ constructor() {
3817
+ this.promise = new Promise((resolve20, reject) => {
3818
+ this.resolve = resolve20;
3819
+ this.reject = reject;
3820
+ });
3821
+ }
3822
+ };
3823
+ function bytes(texts) {
3824
+ return texts.reduce((sum, text) => sum + text.length, 0);
3825
+ }
3826
+
3827
+ // src/cmd/translate/extract.ts
3652
3828
  var command2 = "extract";
3653
3829
  var description2 = "extract xliff and skeleton from yfm documentation";
3654
- var extract2 = { command: command2, description: description2, handler: handler3, builder: builder3 };
3830
+ var extract3 = { command: command2, description: description2, handler: handler3, builder: builder3 };
3655
3831
  var MAX_CONCURRENCY = 50;
3656
3832
  function builder3(argv) {
3657
- return argv.option("source-language-locale", {
3658
- alias: "sll",
3659
- describe: "source language and locale",
3660
- type: "string"
3661
- }).option("target-language-locale", {
3662
- alias: "tll",
3663
- describe: "target language and locale",
3664
- type: "string"
3665
- }).option("input", {
3833
+ return argv.option("input", {
3666
3834
  alias: "i",
3667
- describe: "input folder with markdown files",
3668
- type: "string"
3835
+ describe: "input folder with xliff and skeleton files",
3836
+ type: "string",
3837
+ default: process.cwd()
3669
3838
  }).option("output", {
3670
3839
  alias: "o",
3671
- describe: "output folder to store xliff and skeleton files",
3840
+ describe: "output folder where translated markdown will be stored",
3841
+ type: "string"
3842
+ }).option("source", {
3843
+ alias: ["sll", "source-language-locale"],
3844
+ describe: "source language and locale",
3845
+ type: "string"
3846
+ }).option("target", {
3847
+ alias: ["tll", "target-language-locale"],
3848
+ describe: "target language and locale",
3672
3849
  type: "string"
3673
3850
  }).check(argvValidator);
3674
3851
  }
3675
3852
  function handler3(args) {
3676
3853
  return __async(this, null, function* () {
3677
- args = Object.assign({}, args.translate || {}, args);
3678
- delete args.translate;
3679
- argv_default.init(__spreadValues({}, args));
3680
- const {
3681
- output,
3682
- exclude = [],
3683
- sourceLanguage,
3684
- sourceLocale,
3685
- targetLanguage,
3686
- targetLocale
3687
- } = argv_default.getConfig();
3688
- let {
3689
- input,
3690
- include = [],
3691
- sourceLanguageLocale,
3692
- targetLanguageLocale
3693
- } = argv_default.getConfig();
3694
- (0, import_assert.ok)(input);
3695
- (0, import_assert.ok)(output);
3696
- (0, import_assert.ok)(
3697
- sourceLanguageLocale || sourceLanguage && sourceLocale,
3698
- "Source language and locale should be configured"
3699
- );
3700
- (0, import_assert.ok)(
3701
- targetLanguageLocale || targetLanguage && targetLocale,
3702
- "Source language and locale should be configured"
3703
- );
3704
- sourceLanguageLocale = sourceLanguageLocale || sourceLanguage + "-" + sourceLocale;
3705
- targetLanguageLocale = targetLanguageLocale || targetLanguage + "-" + targetLocale;
3706
- const source = parseLanguageLocale(sourceLanguageLocale);
3707
- const target = parseLanguageLocale(targetLanguageLocale);
3708
- if (input.endsWith(".md")) {
3709
- include = [(0, import_path30.basename)(input)];
3710
- input = (0, import_path30.dirname)(input);
3711
- } else if (!include.length) {
3712
- include.push("**/*");
3854
+ var _a;
3855
+ const params = normalizeParams(__spreadValues(__spreadValues(__spreadValues({}, args.translate || {}), ((_a = args.translate) == null ? void 0 : _a.extract) || {}), args));
3856
+ argv_default.init(params);
3857
+ const { input, output, source, targets, files } = argv_default.getConfig();
3858
+ (0, import_assert2.ok)(source, `Required param source is not configured`);
3859
+ (0, import_assert2.ok)(targets.length, `Required param target is not configured`);
3860
+ for (const target of targets) {
3861
+ const [sourceLanguage, sourceLocale] = source;
3862
+ const [targetLanguage, targetLocale] = target;
3863
+ (0, import_assert2.ok)(sourceLanguage && sourceLocale, "Invalid source language-locale config");
3864
+ (0, import_assert2.ok)(targetLanguage && targetLocale, "Invalid target language-locale config");
3865
+ const configuredPipeline = pipeline2({
3866
+ source: { language: sourceLanguage, locale: sourceLocale },
3867
+ target: { language: targetLanguage, locale: targetLocale },
3868
+ input,
3869
+ output
3870
+ });
3871
+ yield (0, import_async3.eachLimit)(files, MAX_CONCURRENCY, (0, import_async3.asyncify)(configuredPipeline));
3713
3872
  }
3714
- const files = [].concat(
3715
- ...include.map(
3716
- (match) => import_glob4.default.sync(match, {
3717
- cwd: (0, import_path30.join)(input, source.language),
3718
- ignore: exclude
3719
- })
3720
- )
3721
- );
3722
- const found = [...new Set(files)];
3723
- const configuredPipeline = pipeline2({ source, target, input, output });
3724
- yield (0, import_async3.eachLimit)(found, MAX_CONCURRENCY, (0, import_async3.asyncify)(configuredPipeline));
3725
3873
  });
3726
3874
  }
3727
- function parseLanguageLocale(languageLocale) {
3728
- const [language, locale] = languageLocale.split("-");
3729
- if (!(language == null ? void 0 : language.length) || !(locale == null ? void 0 : locale.length)) {
3730
- throw new Error("invalid language-locale string");
3731
- }
3732
- return { language, locale };
3733
- }
3734
3875
  function pipeline2(params) {
3735
3876
  const { input, output, source, target } = params;
3736
- const inputRoot = (0, import_path30.resolve)(input, source.language);
3737
- const outputRoot = (0, import_path30.resolve)(output, target.language);
3877
+ const inputRoot = (0, import_path32.resolve)(input);
3878
+ const outputRoot = (0, import_path32.resolve)(output);
3738
3879
  return (path) => __async(this, null, function* () {
3739
- if (!path.endsWith(".md")) {
3880
+ const ext = (0, import_path32.extname)(path);
3881
+ if (![".yaml", ".json", ".md"].includes(ext)) {
3740
3882
  return;
3741
3883
  }
3742
- const inputPath = (0, import_path30.join)(inputRoot, path);
3743
- const xliffPath = (0, import_path30.join)(outputRoot, path + ".xliff");
3744
- const skeletonPath = (0, import_path30.join)(outputRoot, path + ".skl");
3745
- const markdown = yield readFile3(inputPath, "utf-8");
3746
- yield mkdir2((0, import_path30.dirname)(xliffPath), { recursive: true });
3747
- const { xliff: xliff2, skeleton } = yield (0, import_markdown_translation.extract)({
3748
- markdownPath: path,
3749
- skeletonPath,
3750
- markdown,
3884
+ const inputPath = (0, import_path32.join)(inputRoot, path);
3885
+ const outputPath = path.replace(source.language, target.language);
3886
+ const xliffPath = (0, import_path32.join)(outputRoot, outputPath + ".xliff");
3887
+ const skeletonPath = (0, import_path32.join)(outputRoot, outputPath + ".skl");
3888
+ let schemas;
3889
+ if ([".yaml", ".json"].includes(ext)) {
3890
+ schemas = resolveSchemas(path);
3891
+ if (!schemas) {
3892
+ return;
3893
+ }
3894
+ }
3895
+ const content = yield loadFile(inputPath);
3896
+ yield (0, import_promises4.mkdir)((0, import_path32.dirname)(xliffPath), { recursive: true });
3897
+ const { xliff, skeleton } = (0, import_translation3.extract)(content, {
3751
3898
  source,
3752
3899
  target
3753
3900
  });
3754
- yield Promise.all([writeFile2(skeletonPath, skeleton), writeFile2(xliffPath, xliff2)]);
3901
+ yield Promise.all([dumpFile(skeletonPath, skeleton), dumpFile(xliffPath, xliff)]);
3755
3902
  });
3756
3903
  }
3757
3904
 
3758
- // src/cmd/xliff/compose.ts
3759
- var import_assert2 = require("assert");
3760
- var import_glob5 = __toESM(require("glob"));
3761
- var import_path31 = require("path");
3762
- var import_markdown_translation2 = require("@diplodoc/markdown-translation");
3905
+ // src/cmd/translate/compose.ts
3906
+ var import_promises5 = require("fs/promises");
3907
+ var import_path33 = require("path");
3763
3908
  var import_async4 = require("async");
3764
- var {
3765
- promises: { readFile: readFile4, writeFile: writeFile3, mkdir: mkdir3 }
3766
- } = require("fs");
3909
+ var import_translation4 = require("@diplodoc/translation");
3767
3910
  var command3 = "compose";
3768
3911
  var description3 = "compose xliff and skeleton into documentation";
3769
- var compose = { command: command3, description: description3, handler: handler4, builder: builder4 };
3912
+ var compose2 = { command: command3, description: description3, handler: handler4, builder: builder4 };
3770
3913
  var MAX_CONCURRENCY2 = 50;
3771
3914
  function builder4(argv) {
3772
3915
  return argv.option("input", {
3773
3916
  alias: "i",
3774
3917
  describe: "input folder with xliff and skeleton files",
3775
- type: "string"
3918
+ type: "string",
3919
+ default: process.cwd()
3776
3920
  }).option("output", {
3777
3921
  alias: "o",
3778
3922
  describe: "output folder where translated markdown will be stored",
3779
3923
  type: "string"
3780
- }).option("target-language", {
3781
- alias: "tl",
3782
- describe: "target language",
3783
- type: "string"
3784
3924
  }).option("use-source", {
3785
3925
  describe: "for debug",
3786
3926
  type: "boolean"
@@ -3788,115 +3928,86 @@ function builder4(argv) {
3788
3928
  }
3789
3929
  function handler4(args) {
3790
3930
  return __async(this, null, function* () {
3791
- args = Object.assign({}, args.translate || {}, args);
3792
- delete args.translate;
3793
- argv_default.init(__spreadValues({}, args));
3931
+ var _a;
3932
+ const params = normalizeParams(
3933
+ __spreadValues(__spreadValues(__spreadValues({}, args.translate || {}), ((_a = args.translate) == null ? void 0 : _a.compose) || {}), args),
3934
+ [".skl", ".xliff"]
3935
+ );
3936
+ argv_default.init(params);
3794
3937
  const {
3795
3938
  input,
3796
3939
  output,
3797
- exclude = [],
3798
- targetLanguage,
3940
+ files,
3799
3941
  useSource = false
3800
3942
  } = argv_default.getConfig();
3801
- (0, import_assert2.ok)(input);
3802
- (0, import_assert2.ok)(output);
3803
- (0, import_assert2.ok)(targetLanguage);
3804
- const skeletons = import_glob5.default.sync("**/*.skl", {
3805
- cwd: (0, import_path31.join)(input, targetLanguage),
3806
- ignore: exclude
3807
- });
3808
- const xliffs = import_glob5.default.sync("**/*.xliff", {
3809
- cwd: (0, import_path31.join)(input, targetLanguage),
3810
- ignore: exclude
3811
- });
3812
- (0, import_assert2.ok)(xliffs.length === skeletons.length, "Inconsistent number of xliff and skeleton files.");
3813
- const pipelineParameters = { input, output, targetLanguage, useSource };
3814
- const configuredPipeline = pipeline3(pipelineParameters);
3815
- yield (0, import_async4.eachLimit)(skeletons, MAX_CONCURRENCY2, configuredPipeline);
3943
+ const pairs = files.reduce(
3944
+ (acc, file) => {
3945
+ const ext = (0, import_path33.extname)(file);
3946
+ const path = file.slice(0, -ext.length);
3947
+ acc[path] = acc[path] || { path, ext };
3948
+ acc[path][ext.slice(1)] = file;
3949
+ return acc;
3950
+ },
3951
+ {}
3952
+ );
3953
+ const configuredPipeline = pipeline3(input, output, { useSource });
3954
+ yield (0, import_async4.eachLimit)(pairs, MAX_CONCURRENCY2, configuredPipeline);
3816
3955
  });
3817
3956
  }
3818
- function pipeline3(params) {
3819
- const { input, output, targetLanguage, useSource } = params;
3820
- return (skeletonPath) => __async(this, null, function* () {
3821
- const fileName = skeletonPath.split(".").slice(0, -1).join(".");
3822
- const xliffPath = fileName + ".xliff";
3823
- const [skeleton, xliff2] = yield Promise.all([
3824
- readFile4((0, import_path31.join)(input, targetLanguage, skeletonPath), "utf-8"),
3825
- readFile4((0, import_path31.join)(input, targetLanguage, xliffPath), "utf-8")
3957
+ function pipeline3(input, output, { useSource }) {
3958
+ return (file) => __async(this, null, function* () {
3959
+ const [skeleton, xliff] = yield Promise.all([
3960
+ loadFile((0, import_path33.join)(input, file.skl)),
3961
+ loadFile((0, import_path33.join)(input, file.xliff))
3826
3962
  ]);
3827
- const markdown = (0, import_markdown_translation2.compose)({
3828
- skeleton,
3829
- xliff: xliff2,
3830
- skeletonPath,
3831
- xliffPath,
3832
- useSource
3833
- });
3834
- const markdownPath = (0, import_path31.join)(output, targetLanguage, fileName);
3835
- yield mkdir3((0, import_path31.dirname)(markdownPath), { recursive: true });
3836
- yield writeFile3(markdownPath, markdown);
3963
+ let schemas;
3964
+ if ([".yaml", ".json"].includes(file.ext)) {
3965
+ schemas = resolveSchemas(file.path);
3966
+ if (!schemas) {
3967
+ return;
3968
+ }
3969
+ }
3970
+ const result = (0, import_translation4.compose)(skeleton, xliff, { useSource, schemas });
3971
+ const filePath = (0, import_path33.join)(output, file.path);
3972
+ yield (0, import_promises5.mkdir)((0, import_path33.dirname)(filePath), { recursive: true });
3973
+ yield dumpFile(filePath, result);
3837
3974
  });
3838
3975
  }
3839
3976
 
3840
- // src/cmd/xliff/index.ts
3841
- var command4 = "xliff";
3842
- var description4 = "extract xliff and skeleton from documentation files\ncompose xliff and skeleton into documentation";
3843
- var xliff = {
3844
- command: command4,
3845
- description: description4,
3846
- handler: () => {
3847
- },
3848
- builder: builder5
3849
- };
3850
- function builder5(argv) {
3851
- return argv.command(extract2).command(compose).demandCommand(
3852
- 1,
3853
- `provide one of the folowing ${command4} commands: ${extract2.command}, ${compose.command}`
3854
- );
3855
- }
3856
-
3857
3977
  // src/cmd/translate/handler.ts
3978
+ var import_axios = __toESM(require("axios"));
3858
3979
  var import_assert3 = require("assert");
3859
- var import_path33 = require("path");
3860
- var import_glob6 = __toESM(require("glob"));
3980
+ var import_path34 = require("path");
3981
+ var import_promises6 = require("fs/promises");
3861
3982
 
3862
- // src/packages/credentials/yandex-oauth.ts
3863
- var import_promises3 = require("fs/promises");
3864
- var import_process3 = require("process");
3865
- var import_os = require("os");
3866
- var import_path32 = require("path");
3867
- var YANDEX_OAUTH_TOKEN_FILENAME = ".ya_oauth_token";
3868
- function getYandexOAuthToken() {
3869
- return __async(this, null, function* () {
3870
- const { YANDEX_OAUTH_TOKEN } = import_process3.env;
3871
- return YANDEX_OAUTH_TOKEN != null ? YANDEX_OAUTH_TOKEN : getYandexOAuthTokenFromHomeDir();
3872
- });
3873
- }
3874
- function getYandexOAuthTokenFromHomeDir() {
3875
- return __async(this, null, function* () {
3876
- const error = "failed reading yandex oauth token";
3877
- const path = (0, import_path32.join)((0, import_os.homedir)(), YANDEX_OAUTH_TOKEN_FILENAME);
3878
- let token;
3879
- try {
3880
- token = yield (0, import_promises3.readFile)(path, { encoding: "utf8" });
3881
- token = token.trim();
3882
- if (!(token == null ? void 0 : token.length)) {
3883
- throw new Error(error);
3884
- }
3885
- } catch (err) {
3886
- logger.error(error);
3887
- throw err;
3888
- }
3889
- return token;
3890
- });
3983
+ // src/cmd/translate/yandex/auth.ts
3984
+ var import_fs14 = require("fs");
3985
+ var resolveKey = (data) => {
3986
+ switch (true) {
3987
+ case data.startsWith("y0_"):
3988
+ return "Bearer " + data;
3989
+ case data.startsWith("t1."):
3990
+ return "Bearer " + data;
3991
+ case data.startsWith("AQVN"):
3992
+ return "Api-Key " + data;
3993
+ default:
3994
+ return null;
3995
+ }
3996
+ };
3997
+ function getYandexAuth(path) {
3998
+ let auth = resolveKey(path);
3999
+ if (auth !== null) {
4000
+ return auth;
4001
+ }
4002
+ auth = resolveKey((0, import_fs14.readFileSync)(path, "utf8"));
4003
+ if (auth === null) {
4004
+ throw new Error("No Auth");
4005
+ }
4006
+ return auth;
3891
4007
  }
3892
4008
 
3893
4009
  // src/cmd/translate/handler.ts
3894
4010
  var import_async5 = require("async");
3895
- var import_session = require("@yandex-cloud/nodejs-sdk/dist/session");
3896
- var import_service_clients = require("@yandex-cloud/nodejs-sdk/dist/generated/yandex/cloud/service_clients");
3897
- var import_translation_service = require("@yandex-cloud/nodejs-sdk/dist/generated/yandex/cloud/ai/translate/v2/translation_service");
3898
- var import_promises4 = require("fs/promises");
3899
- var import_markdown_translation3 = require("@diplodoc/markdown-translation");
3900
4011
  var REQUESTS_LIMIT = 20;
3901
4012
  var BYTES_LIMIT = 1e4;
3902
4013
  var RETRY_LIMIT = 3;
@@ -3906,230 +4017,225 @@ var TranslatorError = class extends Error {
3906
4017
  this.path = path;
3907
4018
  }
3908
4019
  };
4020
+ var RequestError = class extends Error {
4021
+ constructor(error) {
4022
+ super((error == null ? void 0 : error.message) || String(error));
4023
+ this.code = "REQUEST_ERROR";
4024
+ }
4025
+ };
3909
4026
  function handler5(args) {
3910
4027
  return __async(this, null, function* () {
3911
- argv_default.init(__spreadValues(__spreadValues({}, args.translate || {}), args));
3912
- const {
3913
- folderId,
3914
- // yandexCloudTranslateGlossaryPairs,
3915
- sourceLanguage,
3916
- targetLanguage,
3917
- exclude = []
3918
- } = argv_default.getConfig();
3919
- let { input, output, include = [] } = argv_default.getConfig();
3920
- logger.info(
3921
- input,
3922
- `translating documentation from ${sourceLanguage} to ${targetLanguage} language`
3923
- );
3924
- output = output || input;
3925
- (0, import_assert3.ok)(input, "Required param input is not configured");
3926
- (0, import_assert3.ok)(sourceLanguage, "Required param sourceLanguage is not configured");
3927
- (0, import_assert3.ok)(targetLanguage, "Required param targetLanguage is not configured");
4028
+ const params = normalizeParams(__spreadValues(__spreadValues({}, args.translate || {}), args));
4029
+ argv_default.init(params);
4030
+ const { input, output, auth, folder, source, targets, files, dryRun } = argv_default.getConfig();
4031
+ (0, import_assert3.ok)(auth, "Required param auth is not configured");
4032
+ (0, import_assert3.ok)(folder, "Required param folder is not configured");
4033
+ (0, import_assert3.ok)(source, `Required param source is not configured`);
4034
+ (0, import_assert3.ok)(targets.length, `Required param target is not configured`);
3928
4035
  try {
3929
- if (input.endsWith(".md")) {
3930
- include = [(0, import_path33.basename)(input)];
3931
- input = (0, import_path33.dirname)(input);
3932
- } else if (!include.length) {
3933
- include.push("**/*");
3934
- }
3935
- const files = [].concat(
3936
- ...include.map(
3937
- (match) => import_glob6.default.sync(match, {
3938
- cwd: (0, import_path33.join)(input, sourceLanguage),
3939
- ignore: exclude
4036
+ const authInfo = getYandexAuth(auth);
4037
+ for (const target of targets) {
4038
+ const translatorParams = {
4039
+ input,
4040
+ output,
4041
+ sourceLanguage: source[0],
4042
+ targetLanguage: target[0],
4043
+ // yandexCloudTranslateGlossaryPairs,
4044
+ folderId: folder,
4045
+ auth: authInfo,
4046
+ dryRun
4047
+ };
4048
+ const cache = /* @__PURE__ */ new Map();
4049
+ const request = requester(translatorParams, cache);
4050
+ const split = splitter(request, cache);
4051
+ const translate2 = translator(translatorParams, split);
4052
+ yield (0, import_async5.eachLimit)(
4053
+ files,
4054
+ REQUESTS_LIMIT,
4055
+ (0, import_async5.asyncify)(function(file) {
4056
+ return __async(this, null, function* () {
4057
+ try {
4058
+ yield translate2(file);
4059
+ } catch (error) {
4060
+ logger.error(file, error.message);
4061
+ }
4062
+ });
3940
4063
  })
3941
- )
3942
- );
3943
- const found = [...new Set(files)];
3944
- const oauthToken = yield getYandexOAuthToken();
3945
- const translatorParams = {
3946
- input,
3947
- output,
3948
- sourceLanguage,
3949
- targetLanguage,
3950
- // yandexCloudTranslateGlossaryPairs,
3951
- folderId,
3952
- oauthToken
3953
- };
3954
- const translateFn = translator(translatorParams);
3955
- yield (0, import_async5.eachLimit)(found, REQUESTS_LIMIT, (0, import_async5.asyncify)(translateFn));
3956
- } catch (err) {
3957
- if (err instanceof Error || err instanceof TranslatorError) {
3958
- const message = err.message;
3959
- const file = err instanceof TranslatorError ? err.path : "";
3960
- logger.error(file, message);
4064
+ );
4065
+ console.log("PROCESSED", `bytes: ${request.stat.bytes} chunks: ${request.stat.chunks}`);
3961
4066
  }
4067
+ } catch (error) {
4068
+ const message = error.message;
4069
+ const file = error instanceof TranslatorError ? error.path : "";
4070
+ logger.error(file, message);
3962
4071
  }
3963
- logger.info(
3964
- output,
3965
- `translated documentation from ${sourceLanguage} to ${targetLanguage} language`
3966
- );
3967
4072
  });
3968
4073
  }
3969
- function translator(params) {
3970
- const {
3971
- oauthToken,
3972
- folderId,
3973
- input,
3974
- output,
3975
- sourceLanguage,
3976
- targetLanguage
3977
- // yandexCloudTranslateGlossaryPairs,
3978
- } = params;
3979
- const tmap = /* @__PURE__ */ new Map();
3980
- const session = new import_session.Session({ oauthToken });
3981
- const client = session.client(import_service_clients.TranslationServiceClient);
3982
- const request = (texts) => () => {
3983
- return client.translate(
3984
- import_translation_service.TranslateRequest.fromPartial({
3985
- texts,
3986
- folderId,
3987
- sourceLanguageCode: sourceLanguage,
3988
- targetLanguageCode: targetLanguage,
3989
- // glossaryConfig: {
3990
- // glossaryData: {
3991
- // glossaryPairs: yandexCloudTranslateGlossaryPairs,
3992
- // },
3993
- // },
3994
- format: import_translation_service.TranslateRequest_Format.HTML
3995
- })
3996
- ).then((results) => {
3997
- return results.translations.map(({ text }, index) => {
3998
- const defer = tmap.get(texts[index]);
3999
- if (defer) {
4000
- defer.resolve([text]);
4074
+ function requester(params, cache) {
4075
+ const { auth, folderId, sourceLanguage, targetLanguage, dryRun } = params;
4076
+ const resolve20 = (text, index, texts) => {
4077
+ const defer = cache.get(texts[index]);
4078
+ if (defer) {
4079
+ defer.resolve(text);
4080
+ }
4081
+ return text;
4082
+ };
4083
+ const request = function request2(texts) {
4084
+ request2.stat.bytes += bytes(texts);
4085
+ request2.stat.chunks++;
4086
+ return function() {
4087
+ return __async(this, null, function* () {
4088
+ if (dryRun) {
4089
+ return texts.map(resolve20);
4001
4090
  }
4002
- return text;
4091
+ return (0, import_axios.default)({
4092
+ method: "POST",
4093
+ url: "https://translate.api.cloud.yandex.net/translate/v2/translate",
4094
+ headers: {
4095
+ "Content-Type": "application/json",
4096
+ Authorization: auth
4097
+ },
4098
+ data: {
4099
+ folderId,
4100
+ texts,
4101
+ sourceLanguageCode: sourceLanguage,
4102
+ targetLanguageCode: targetLanguage,
4103
+ format: "HTML"
4104
+ }
4105
+ }).then(({ data, status }) => {
4106
+ if (status === 200) {
4107
+ return data;
4108
+ } else {
4109
+ throw new Error(data.message);
4110
+ }
4111
+ }).then((result) => {
4112
+ return result.translations.map(({ text }, index) => {
4113
+ return resolve20(text, index, texts);
4114
+ });
4115
+ }).catch((error) => {
4116
+ console.error(error);
4117
+ throw new RequestError(error);
4118
+ });
4003
4119
  });
4004
- });
4120
+ };
4121
+ };
4122
+ request.stat = {
4123
+ bytes: 0,
4124
+ chunks: 0
4005
4125
  };
4006
- return (mdPath) => __async(this, null, function* () {
4007
- if (!mdPath.endsWith(".md")) {
4126
+ return request;
4127
+ }
4128
+ function translator(params, split) {
4129
+ const { input, output, sourceLanguage, targetLanguage } = params;
4130
+ const inputRoot = (0, import_path34.resolve)(input);
4131
+ const outputRoot = (0, import_path34.resolve)(output);
4132
+ return (path) => __async(this, null, function* () {
4133
+ const ext = (0, import_path34.extname)(path);
4134
+ if (![".yaml", ".json", ".md"].includes(ext)) {
4008
4135
  return;
4009
4136
  }
4010
- try {
4011
- logger.info(mdPath, "translating");
4012
- const inputPath = (0, import_path33.resolve)(input, sourceLanguage, mdPath);
4013
- const outputPath = (0, import_path33.resolve)(output, targetLanguage, mdPath);
4014
- const md = yield (0, import_promises4.readFile)(inputPath, { encoding: "utf-8" });
4015
- yield (0, import_promises4.mkdir)((0, import_path33.dirname)(outputPath), { recursive: true });
4016
- if (!md) {
4017
- yield (0, import_promises4.writeFile)(outputPath, md);
4018
- return;
4019
- }
4020
- const { units, skeleton } = (0, import_markdown_translation3.extract)({
4021
- source: {
4022
- language: sourceLanguage,
4023
- locale: "RU"
4024
- },
4025
- target: {
4026
- language: targetLanguage,
4027
- locale: "US"
4028
- },
4029
- markdown: md,
4030
- markdownPath: mdPath,
4031
- skeletonPath: ""
4032
- });
4033
- if (!units.length) {
4034
- yield (0, import_promises4.writeFile)(outputPath, md);
4035
- return;
4137
+ const inputPath = (0, import_path34.join)(inputRoot, path);
4138
+ const outputPath = (0, import_path34.join)(outputRoot, path.replace(sourceLanguage, targetLanguage));
4139
+ const content = yield loadFile(inputPath);
4140
+ yield (0, import_promises6.mkdir)((0, import_path34.dirname)(outputPath), { recursive: true });
4141
+ if (!content) {
4142
+ yield dumpFile(outputPath, content);
4143
+ return;
4144
+ }
4145
+ const { units, skeleton } = extract2(content, {
4146
+ source: {
4147
+ language: sourceLanguage,
4148
+ locale: "RU"
4149
+ },
4150
+ target: {
4151
+ language: targetLanguage,
4152
+ locale: "US"
4036
4153
  }
4037
- const parts = yield Promise.all(
4038
- units.reduce(
4039
- ({
4040
- promises,
4041
- buffer,
4042
- bufferSize
4043
- }, text, index) => {
4044
- if (text.length >= BYTES_LIMIT) {
4045
- logger.warn(
4046
- mdPath,
4047
- "Skip document part for translation. Part is too big."
4048
- );
4049
- promises.push(Promise.resolve([text]));
4050
- return { promises, buffer, bufferSize };
4051
- }
4052
- const defer = tmap.get(text);
4053
- if (defer) {
4054
- console.log("SKIPPED", text);
4055
- promises.push(defer.promise);
4056
- return { promises, buffer, bufferSize };
4057
- }
4058
- if (bufferSize + text.length > BYTES_LIMIT) {
4059
- promises.push(backoff(request(buffer)));
4060
- buffer = [];
4061
- bufferSize = 0;
4062
- }
4063
- buffer.push(text);
4064
- bufferSize += text.length;
4065
- tmap.set(text, new Defer());
4066
- if (index === units.length - 1) {
4067
- promises.push(backoff(request(buffer)));
4068
- }
4069
- return { promises, buffer, bufferSize };
4070
- },
4071
- {
4072
- promises: [],
4073
- buffer: [],
4074
- bufferSize: 0
4154
+ });
4155
+ if (!units.length) {
4156
+ yield dumpFile(outputPath, content);
4157
+ return;
4158
+ }
4159
+ const parts = yield Promise.all(split(path, units));
4160
+ const composed = compose(skeleton, parts, { useSource: true });
4161
+ yield dumpFile(outputPath, composed);
4162
+ });
4163
+ }
4164
+ function splitter(request, cache) {
4165
+ return function(path, texts) {
4166
+ const promises = [];
4167
+ let buffer = [];
4168
+ let bufferSize = 0;
4169
+ const release = () => {
4170
+ backoff(request(buffer));
4171
+ buffer = [];
4172
+ bufferSize = 0;
4173
+ };
4174
+ for (const text of texts) {
4175
+ if (text.length >= BYTES_LIMIT) {
4176
+ logger.warn(path, "Skip document part for translation. Part is too big.");
4177
+ promises.push(Promise.resolve(text));
4178
+ } else {
4179
+ const defer = cache.get(text) || new Defer();
4180
+ promises.push(defer.promise);
4181
+ if (!cache.get(text)) {
4182
+ if (bufferSize + text.length > BYTES_LIMIT) {
4183
+ release();
4075
4184
  }
4076
- ).promises
4077
- );
4078
- const translations = [].concat(...parts);
4079
- const composed = yield (0, import_markdown_translation3.compose)({
4080
- useSource: true,
4081
- units: translations,
4082
- skeleton
4083
- });
4084
- yield (0, import_promises4.writeFile)(outputPath, composed);
4085
- logger.info(outputPath, "finished translating");
4086
- } catch (err) {
4087
- if (err instanceof Error) {
4088
- throw new TranslatorError(err.toString(), mdPath);
4185
+ buffer.push(text);
4186
+ bufferSize += text.length;
4187
+ }
4188
+ cache.set(text, defer);
4089
4189
  }
4090
4190
  }
4091
- });
4191
+ if (bufferSize) {
4192
+ release();
4193
+ }
4194
+ return promises;
4195
+ };
4092
4196
  }
4093
4197
  function backoff(action) {
4094
4198
  return (0, import_async5.retry)(
4095
4199
  {
4096
4200
  times: RETRY_LIMIT,
4097
- interval: (count) => {
4098
- return (1 << count) * 1e3;
4099
- }
4201
+ interval: (count) => Math.pow(2, count) * 1e3
4100
4202
  },
4101
4203
  (0, import_async5.asyncify)(action)
4102
4204
  );
4103
4205
  }
4104
- var Defer = class {
4105
- constructor() {
4106
- this.promise = new Promise((resolve19, reject) => {
4107
- this.resolve = resolve19;
4108
- this.reject = reject;
4109
- });
4110
- }
4111
- };
4112
4206
 
4113
4207
  // src/cmd/translate/index.ts
4114
- var command5 = "translate";
4115
- var description5 = "translate documentation with Yandex.Cloud Translator API";
4208
+ var command4 = "translate";
4209
+ var description4 = "translate documentation with Yandex.Cloud Translator API";
4116
4210
  var translate = {
4117
- command: command5,
4118
- description: description5,
4211
+ command: command4,
4212
+ description: description4,
4119
4213
  handler: handler5,
4120
- builder: builder6
4214
+ builder: builder5
4121
4215
  };
4122
- function builder6(argv) {
4123
- return argv.command(extract2).command(compose).option("folder-id", {
4124
- describe: "folder id",
4216
+ function builder5(argv) {
4217
+ return argv.command(extract3).command(compose2).option("input", {
4218
+ alias: "i",
4219
+ describe: "input folder with markdown files",
4220
+ type: "string",
4221
+ default: process.cwd()
4222
+ }).option("output", {
4223
+ alias: "o",
4224
+ describe: "output folder to store xliff and skeleton files",
4125
4225
  type: "string"
4126
- }).option("source-language", {
4127
- alias: "sl",
4128
- describe: "source language code",
4226
+ }).option("auth", {
4227
+ describe: "auth credentials path",
4129
4228
  type: "string"
4130
- }).option("target-language", {
4131
- alias: "tl",
4132
- describe: "target language code",
4229
+ }).option("folder", {
4230
+ describe: "folder",
4231
+ type: "string"
4232
+ }).option("source", {
4233
+ alias: ["sl", "sll", "source-language", "source-language-locale"],
4234
+ describe: "source language and locale",
4235
+ type: "string"
4236
+ }).option("target", {
4237
+ alias: ["tl", "tll", "target-language", "target-language-locale"],
4238
+ describe: "target language and locale",
4133
4239
  type: "string"
4134
4240
  }).option("include", {
4135
4241
  describe: "relative to input globs to include in processing",
@@ -4137,12 +4243,15 @@ function builder6(argv) {
4137
4243
  }).option("exclude", {
4138
4244
  describe: "relative to input globs to exclude from processing",
4139
4245
  type: "string"
4246
+ }).option("dry-run", {
4247
+ describe: "check command usage",
4248
+ type: "boolean"
4140
4249
  }).check(argvValidator);
4141
4250
  }
4142
4251
 
4143
4252
  // src/index.ts
4144
4253
  console.time(MAIN_TIMER_ID);
4145
- import_yargs.default.command(build).command(publish).command(xliff).command(translate).option("config", {
4254
+ import_yargs.default.command(build).command(publish).command(translate).option("config", {
4146
4255
  alias: "c",
4147
4256
  describe: "YFM configuration file",
4148
4257
  type: "string"
@@ -4156,7 +4265,7 @@ import_yargs.default.command(build).command(publish).command(xliff).command(tran
4156
4265
  default: false,
4157
4266
  describe: "Run in quiet mode. Don't write logs to stdout",
4158
4267
  type: "boolean"
4159
- }).group(["config", "strict", "quiet", "help", "version"], "Common options:").version(true ? "4.13.6" : "").help().parse((0, import_helpers.hideBin)(process.argv), {}, (err, { strict }, output) => {
4268
+ }).group(["config", "strict", "quiet", "help", "version"], "Common options:").version(true ? "4.13.8" : "").help().parse((0, import_helpers.hideBin)(process.argv), {}, (err, { strict }, output) => {
4160
4269
  console.timeEnd(MAIN_TIMER_ID);
4161
4270
  if (err) {
4162
4271
  console.error(err);