@diplodoc/cli 4.13.5 → 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/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,292 @@ 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
+ function flat(parts) {
3816
+ return [].concat(...parts);
3817
+ }
3818
+ var Defer = class {
3819
+ constructor() {
3820
+ this.promise = new Promise((resolve20, reject) => {
3821
+ this.resolve = resolve20;
3822
+ this.reject = reject;
3823
+ });
3824
+ }
3825
+ };
3826
+ function bytes(texts) {
3827
+ return texts.reduce((sum, text) => sum + text.length, 0);
3828
+ }
3829
+
3830
+ // src/cmd/translate/extract.ts
3652
3831
  var command2 = "extract";
3653
3832
  var description2 = "extract xliff and skeleton from yfm documentation";
3654
- var extract2 = { command: command2, description: description2, handler: handler3, builder: builder3 };
3833
+ var extract3 = { command: command2, description: description2, handler: handler3, builder: builder3 };
3655
3834
  var MAX_CONCURRENCY = 50;
3656
3835
  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", {
3836
+ return argv.option("input", {
3666
3837
  alias: "i",
3667
- describe: "input folder with markdown files",
3668
- type: "string"
3838
+ describe: "input folder with xliff and skeleton files",
3839
+ type: "string",
3840
+ default: process.cwd()
3669
3841
  }).option("output", {
3670
3842
  alias: "o",
3671
- describe: "output folder to store xliff and skeleton files",
3843
+ describe: "output folder where translated markdown will be stored",
3844
+ type: "string",
3845
+ default: process.cwd()
3846
+ }).option("source", {
3847
+ alias: ["sll", "source-language-locale"],
3848
+ describe: "source language and locale",
3849
+ type: "string"
3850
+ }).option("target", {
3851
+ alias: ["tll", "target-language-locale"],
3852
+ describe: "target language and locale",
3672
3853
  type: "string"
3673
3854
  }).check(argvValidator);
3674
3855
  }
3675
3856
  function handler3(args) {
3676
3857
  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("**/*");
3858
+ var _a;
3859
+ const params = normalizeParams(__spreadValues(__spreadValues(__spreadValues({}, args.translate || {}), ((_a = args.translate) == null ? void 0 : _a.extract) || {}), args));
3860
+ argv_default.init(params);
3861
+ const { input, output, source, targets, files } = argv_default.getConfig();
3862
+ (0, import_assert2.ok)(source, `Required param source is not configured`);
3863
+ (0, import_assert2.ok)(targets.length, `Required param target is not configured`);
3864
+ for (const target of targets) {
3865
+ const [sourceLanguage, sourceLocale] = source;
3866
+ const [targetLanguage, targetLocale] = target;
3867
+ (0, import_assert2.ok)(sourceLanguage && sourceLocale, "Invalid source language-locale config");
3868
+ (0, import_assert2.ok)(targetLanguage && targetLocale, "Invalid target language-locale config");
3869
+ const configuredPipeline = pipeline2({
3870
+ source: { language: sourceLanguage, locale: sourceLocale },
3871
+ target: { language: targetLanguage, locale: targetLocale },
3872
+ input,
3873
+ output
3874
+ });
3875
+ yield (0, import_async3.eachLimit)(files, MAX_CONCURRENCY, (0, import_async3.asyncify)(configuredPipeline));
3713
3876
  }
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
3877
  });
3726
3878
  }
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
3879
  function pipeline2(params) {
3735
3880
  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);
3881
+ const inputRoot = (0, import_path32.resolve)(input);
3882
+ const outputRoot = (0, import_path32.resolve)(output);
3738
3883
  return (path) => __async(this, null, function* () {
3739
- if (!path.endsWith(".md")) {
3884
+ const ext = (0, import_path32.extname)(path);
3885
+ if (![".yaml", ".json", ".md"].includes(ext)) {
3740
3886
  return;
3741
3887
  }
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,
3888
+ const inputPath = (0, import_path32.join)(inputRoot, path);
3889
+ const outputPath = path.replace(source.language, target.language);
3890
+ const xliffPath = (0, import_path32.join)(outputRoot, outputPath + ".xliff");
3891
+ const skeletonPath = (0, import_path32.join)(outputRoot, outputPath + ".skl");
3892
+ let schemas;
3893
+ if ([".yaml", ".json"].includes(ext)) {
3894
+ schemas = resolveSchemas(path);
3895
+ if (!schemas) {
3896
+ return;
3897
+ }
3898
+ }
3899
+ const content = yield loadFile(inputPath);
3900
+ yield (0, import_promises4.mkdir)((0, import_path32.dirname)(xliffPath), { recursive: true });
3901
+ const { xliff, skeleton } = (0, import_translation3.extract)(content, {
3751
3902
  source,
3752
3903
  target
3753
3904
  });
3754
- yield Promise.all([writeFile2(skeletonPath, skeleton), writeFile2(xliffPath, xliff2)]);
3905
+ yield Promise.all([dumpFile(skeletonPath, skeleton), dumpFile(xliffPath, xliff)]);
3755
3906
  });
3756
3907
  }
3757
3908
 
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");
3909
+ // src/cmd/translate/compose.ts
3910
+ var import_promises5 = require("fs/promises");
3911
+ var import_path33 = require("path");
3763
3912
  var import_async4 = require("async");
3764
- var {
3765
- promises: { readFile: readFile4, writeFile: writeFile3, mkdir: mkdir3 }
3766
- } = require("fs");
3913
+ var import_translation4 = require("@diplodoc/translation");
3767
3914
  var command3 = "compose";
3768
3915
  var description3 = "compose xliff and skeleton into documentation";
3769
- var compose = { command: command3, description: description3, handler: handler4, builder: builder4 };
3916
+ var compose2 = { command: command3, description: description3, handler: handler4, builder: builder4 };
3770
3917
  var MAX_CONCURRENCY2 = 50;
3771
3918
  function builder4(argv) {
3772
3919
  return argv.option("input", {
3773
3920
  alias: "i",
3774
3921
  describe: "input folder with xliff and skeleton files",
3775
- type: "string"
3922
+ type: "string",
3923
+ default: process.cwd()
3776
3924
  }).option("output", {
3777
3925
  alias: "o",
3778
3926
  describe: "output folder where translated markdown will be stored",
3779
- type: "string"
3780
- }).option("target-language", {
3781
- alias: "tl",
3782
- describe: "target language",
3783
- type: "string"
3927
+ type: "string",
3928
+ default: process.cwd()
3784
3929
  }).option("use-source", {
3785
3930
  describe: "for debug",
3786
3931
  type: "boolean"
@@ -3788,106 +3933,85 @@ function builder4(argv) {
3788
3933
  }
3789
3934
  function handler4(args) {
3790
3935
  return __async(this, null, function* () {
3791
- args = Object.assign({}, args.translate || {}, args);
3792
- delete args.translate;
3793
- argv_default.init(__spreadValues({}, args));
3936
+ var _a;
3937
+ const params = normalizeParams(
3938
+ __spreadValues(__spreadValues(__spreadValues({}, args.translate || {}), ((_a = args.translate) == null ? void 0 : _a.compose) || {}), args),
3939
+ [".skl", ".xliff"]
3940
+ );
3941
+ argv_default.init(params);
3794
3942
  const {
3795
3943
  input,
3796
3944
  output,
3797
- exclude = [],
3798
- targetLanguage,
3945
+ files,
3799
3946
  useSource = false
3800
3947
  } = 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);
3948
+ const pairs = files.reduce(
3949
+ (acc, file) => {
3950
+ const ext = (0, import_path33.extname)(file);
3951
+ const path = file.slice(0, -ext.length);
3952
+ acc[path] = acc[path] || { path, ext };
3953
+ acc[path][ext.slice(1)] = file;
3954
+ return acc;
3955
+ },
3956
+ {}
3957
+ );
3958
+ const configuredPipeline = pipeline3(input, output, { useSource });
3959
+ yield (0, import_async4.eachLimit)(pairs, MAX_CONCURRENCY2, configuredPipeline);
3816
3960
  });
3817
3961
  }
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")
3962
+ function pipeline3(input, output, { useSource }) {
3963
+ return (file) => __async(this, null, function* () {
3964
+ const [skeleton, xliff] = yield Promise.all([
3965
+ loadFile((0, import_path33.join)(input, file.skl)),
3966
+ loadFile((0, import_path33.join)(input, file.xliff))
3826
3967
  ]);
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);
3968
+ let schemas;
3969
+ if ([".yaml", ".json"].includes(file.ext)) {
3970
+ schemas = resolveSchemas(file.path);
3971
+ if (!schemas) {
3972
+ return;
3973
+ }
3974
+ }
3975
+ const result = (0, import_translation4.compose)(skeleton, xliff, { useSource, schemas });
3976
+ const filePath = (0, import_path33.join)(output, file.path);
3977
+ yield (0, import_promises5.mkdir)((0, import_path33.dirname)(filePath), { recursive: true });
3978
+ yield dumpFile(filePath, result);
3837
3979
  });
3838
3980
  }
3839
3981
 
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
3982
  // src/cmd/translate/handler.ts
3858
3983
  var import_assert3 = require("assert");
3859
- var import_path33 = require("path");
3860
- var import_glob6 = __toESM(require("glob"));
3984
+ var import_path34 = require("path");
3985
+ var import_promises6 = require("fs/promises");
3861
3986
 
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;
3987
+ // src/cmd/translate/yandex/auth.ts
3988
+ var import_fs14 = require("fs");
3989
+ function getYandexAuth(path) {
3990
+ if (path.startsWith("y0_")) {
3991
+ return {
3992
+ oauthToken: path
3993
+ };
3994
+ }
3995
+ const data = (0, import_fs14.readFileSync)(path, "utf8");
3996
+ try {
3997
+ const json = JSON.parse(data);
3998
+ if (isServeseAccount(json)) {
3999
+ return {
4000
+ serviceAccountJson: {
4001
+ serviceAccountId: json.service_account_id,
4002
+ accessKeyId: json.id,
4003
+ privateKey: json.private_key
4004
+ }
4005
+ };
3888
4006
  }
3889
- return token;
3890
- });
4007
+ } catch (e) {
4008
+ }
4009
+ return {
4010
+ oauthToken: data
4011
+ };
4012
+ }
4013
+ function isServeseAccount(json) {
4014
+ return "private_key" in json;
3891
4015
  }
3892
4016
 
3893
4017
  // src/cmd/translate/handler.ts
@@ -3895,8 +4019,6 @@ var import_async5 = require("async");
3895
4019
  var import_session = require("@yandex-cloud/nodejs-sdk/dist/session");
3896
4020
  var import_service_clients = require("@yandex-cloud/nodejs-sdk/dist/generated/yandex/cloud/service_clients");
3897
4021
  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
4022
  var REQUESTS_LIMIT = 20;
3901
4023
  var BYTES_LIMIT = 1e4;
3902
4024
  var RETRY_LIMIT = 3;
@@ -3906,230 +4028,217 @@ var TranslatorError = class extends Error {
3906
4028
  this.path = path;
3907
4029
  }
3908
4030
  };
4031
+ var RequestError = class extends Error {
4032
+ constructor(error) {
4033
+ super((error == null ? void 0 : error.message) || String(error));
4034
+ this.code = "REQUEST_ERROR";
4035
+ }
4036
+ };
3909
4037
  function handler5(args) {
3910
4038
  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");
4039
+ const params = normalizeParams(__spreadValues(__spreadValues({}, args.translate || {}), args));
4040
+ argv_default.init(params);
4041
+ const { input, output, auth, folder, source, targets, files, dryRun } = argv_default.getConfig();
4042
+ (0, import_assert3.ok)(auth, "Required param auth is not configured");
4043
+ (0, import_assert3.ok)(folder, "Required param folder is not configured");
4044
+ (0, import_assert3.ok)(source, `Required param source is not configured`);
4045
+ (0, import_assert3.ok)(targets.length, `Required param target is not configured`);
3928
4046
  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
4047
+ const authInfo = getYandexAuth(auth);
4048
+ for (const target of targets) {
4049
+ const translatorParams = {
4050
+ input,
4051
+ output,
4052
+ sourceLanguage: source[0],
4053
+ targetLanguage: target[0],
4054
+ // yandexCloudTranslateGlossaryPairs,
4055
+ folderId: folder,
4056
+ auth: authInfo,
4057
+ dryRun
4058
+ };
4059
+ const cache = /* @__PURE__ */ new Map();
4060
+ const request = requester(translatorParams, cache);
4061
+ const split = splitter(request, cache);
4062
+ const translate2 = translator(translatorParams, split);
4063
+ yield (0, import_async5.eachLimit)(
4064
+ files,
4065
+ REQUESTS_LIMIT,
4066
+ (0, import_async5.asyncify)(function(file) {
4067
+ return __async(this, null, function* () {
4068
+ try {
4069
+ yield translate2(file);
4070
+ } catch (error) {
4071
+ logger.error(file, error.message);
4072
+ }
4073
+ });
3940
4074
  })
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);
4075
+ );
4076
+ console.log("PROCESSED", `bytes: ${request.stat.bytes} chunks: ${request.stat.chunks}`);
3961
4077
  }
4078
+ } catch (error) {
4079
+ const message = error.message;
4080
+ const file = error instanceof TranslatorError ? error.path : "";
4081
+ logger.error(file, message);
3962
4082
  }
3963
- logger.info(
3964
- output,
3965
- `translated documentation from ${sourceLanguage} to ${targetLanguage} language`
3966
- );
3967
4083
  });
3968
4084
  }
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 });
4085
+ function requester(params, cache) {
4086
+ const { auth, folderId, sourceLanguage, targetLanguage, dryRun } = params;
4087
+ const session = new import_session.Session(auth);
3981
4088
  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]);
4089
+ const resolve20 = (text, index, texts) => {
4090
+ const defer = cache.get(texts[index]);
4091
+ if (defer) {
4092
+ defer.resolve([text]);
4093
+ }
4094
+ return text;
4095
+ };
4096
+ const request = function request2(texts) {
4097
+ request2.stat.bytes += bytes(texts);
4098
+ request2.stat.chunks++;
4099
+ return function() {
4100
+ return __async(this, null, function* () {
4101
+ if (dryRun) {
4102
+ return texts.map(resolve20);
4001
4103
  }
4002
- return text;
4104
+ return client.translate(
4105
+ import_translation_service.TranslateRequest.fromPartial({
4106
+ texts,
4107
+ folderId,
4108
+ sourceLanguageCode: sourceLanguage,
4109
+ targetLanguageCode: targetLanguage,
4110
+ // glossaryConfig: {
4111
+ // glossaryData: {
4112
+ // glossaryPairs: yandexCloudTranslateGlossaryPairs,
4113
+ // },
4114
+ // },
4115
+ format: import_translation_service.TranslateRequest_Format.HTML
4116
+ })
4117
+ ).then((results) => {
4118
+ return results.translations.map(({ text }, index) => {
4119
+ return resolve20(text, index, texts);
4120
+ });
4121
+ }).catch((error) => {
4122
+ console.error(error);
4123
+ throw new RequestError(error);
4124
+ });
4003
4125
  });
4004
- });
4126
+ };
4005
4127
  };
4006
- return (mdPath) => __async(this, null, function* () {
4007
- if (!mdPath.endsWith(".md")) {
4128
+ request.stat = {
4129
+ bytes: 0,
4130
+ chunks: 0
4131
+ };
4132
+ return request;
4133
+ }
4134
+ function translator(params, split) {
4135
+ const { input, output, sourceLanguage, targetLanguage } = params;
4136
+ return (path) => __async(this, null, function* () {
4137
+ const ext = (0, import_path34.extname)(path);
4138
+ if (![".yaml", ".json", ".md"].includes(ext)) {
4008
4139
  return;
4009
4140
  }
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;
4036
- }
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
4075
- }
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);
4141
+ const inputPath = (0, import_path34.resolve)(input, path);
4142
+ const outputPath = (0, import_path34.resolve)(output, path);
4143
+ const content = yield loadFile(inputPath);
4144
+ yield (0, import_promises6.mkdir)((0, import_path34.dirname)(outputPath), { recursive: true });
4145
+ if (!content) {
4146
+ yield dumpFile(outputPath, content);
4147
+ return;
4148
+ }
4149
+ const { units, skeleton } = extract2(content, {
4150
+ source: {
4151
+ language: sourceLanguage,
4152
+ locale: "RU"
4153
+ },
4154
+ target: {
4155
+ language: targetLanguage,
4156
+ locale: "US"
4089
4157
  }
4158
+ });
4159
+ if (!units.length) {
4160
+ yield dumpFile(outputPath, content);
4161
+ return;
4090
4162
  }
4163
+ const parts = flat(yield Promise.all(split(path, units)));
4164
+ const composed = compose(skeleton, parts, { useSource: true });
4165
+ yield dumpFile(outputPath, composed);
4091
4166
  });
4092
4167
  }
4168
+ function splitter(request, cache) {
4169
+ return function(path, texts) {
4170
+ const promises = [];
4171
+ let buffer = [];
4172
+ let bufferSize = 0;
4173
+ const release = () => {
4174
+ promises.push(backoff(request(buffer)));
4175
+ buffer = [];
4176
+ bufferSize = 0;
4177
+ };
4178
+ for (const text of texts) {
4179
+ const defer = cache.get(text);
4180
+ if (defer) {
4181
+ promises.push(defer.promise);
4182
+ } else if (text.length >= BYTES_LIMIT) {
4183
+ logger.warn(path, "Skip document part for translation. Part is too big.");
4184
+ promises.push(Promise.resolve([text]));
4185
+ } else {
4186
+ if (bufferSize + text.length > BYTES_LIMIT) {
4187
+ release();
4188
+ }
4189
+ buffer.push(text);
4190
+ bufferSize += text.length;
4191
+ cache.set(text, new Defer());
4192
+ }
4193
+ }
4194
+ if (bufferSize) {
4195
+ promises.push(backoff(request(buffer)));
4196
+ }
4197
+ return promises;
4198
+ };
4199
+ }
4093
4200
  function backoff(action) {
4094
4201
  return (0, import_async5.retry)(
4095
4202
  {
4096
4203
  times: RETRY_LIMIT,
4097
- interval: (count) => {
4098
- return (1 << count) * 1e3;
4099
- }
4204
+ interval: (count) => Math.pow(2, count) * 1e3
4100
4205
  },
4101
4206
  (0, import_async5.asyncify)(action)
4102
4207
  );
4103
4208
  }
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
4209
 
4113
4210
  // src/cmd/translate/index.ts
4114
- var command5 = "translate";
4115
- var description5 = "translate documentation with Yandex.Cloud Translator API";
4211
+ var command4 = "translate";
4212
+ var description4 = "translate documentation with Yandex.Cloud Translator API";
4116
4213
  var translate = {
4117
- command: command5,
4118
- description: description5,
4214
+ command: command4,
4215
+ description: description4,
4119
4216
  handler: handler5,
4120
- builder: builder6
4217
+ builder: builder5
4121
4218
  };
4122
- function builder6(argv) {
4123
- return argv.command(extract2).command(compose).option("folder-id", {
4124
- describe: "folder id",
4219
+ function builder5(argv) {
4220
+ return argv.command(extract3).command(compose2).option("input", {
4221
+ alias: "i",
4222
+ describe: "input folder with markdown files",
4223
+ type: "string",
4224
+ default: process.cwd()
4225
+ }).option("output", {
4226
+ alias: "o",
4227
+ describe: "output folder to store xliff and skeleton files",
4125
4228
  type: "string"
4126
- }).option("source-language", {
4127
- alias: "sl",
4128
- describe: "source language code",
4229
+ }).option("auth", {
4230
+ describe: "auth credentials path",
4129
4231
  type: "string"
4130
- }).option("target-language", {
4131
- alias: "tl",
4132
- describe: "target language code",
4232
+ }).option("folder", {
4233
+ describe: "folder",
4234
+ type: "string"
4235
+ }).option("source", {
4236
+ alias: ["sl", "sll", "source-language", "source-language-locale"],
4237
+ describe: "source language and locale",
4238
+ type: "string"
4239
+ }).option("target", {
4240
+ alias: ["tl", "tll", "target-language", "target-language-locale"],
4241
+ describe: "target language and locale",
4133
4242
  type: "string"
4134
4243
  }).option("include", {
4135
4244
  describe: "relative to input globs to include in processing",
@@ -4137,12 +4246,15 @@ function builder6(argv) {
4137
4246
  }).option("exclude", {
4138
4247
  describe: "relative to input globs to exclude from processing",
4139
4248
  type: "string"
4249
+ }).option("dry-run", {
4250
+ describe: "check command usage",
4251
+ type: "boolean"
4140
4252
  }).check(argvValidator);
4141
4253
  }
4142
4254
 
4143
4255
  // src/index.ts
4144
4256
  console.time(MAIN_TIMER_ID);
4145
- import_yargs.default.command(build).command(publish).command(xliff).command(translate).option("config", {
4257
+ import_yargs.default.command(build).command(publish).command(translate).option("config", {
4146
4258
  alias: "c",
4147
4259
  describe: "YFM configuration file",
4148
4260
  type: "string"
@@ -4156,7 +4268,7 @@ import_yargs.default.command(build).command(publish).command(xliff).command(tran
4156
4268
  default: false,
4157
4269
  describe: "Run in quiet mode. Don't write logs to stdout",
4158
4270
  type: "boolean"
4159
- }).group(["config", "strict", "quiet", "help", "version"], "Common options:").version(true ? "4.13.5" : "").help().parse((0, import_helpers.hideBin)(process.argv), {}, (err, { strict }, output) => {
4271
+ }).group(["config", "strict", "quiet", "help", "version"], "Common options:").version(true ? "4.13.7" : "").help().parse((0, import_helpers.hideBin)(process.argv), {}, (err, { strict }, output) => {
4160
4272
  console.timeEnd(MAIN_TIMER_ID);
4161
4273
  if (err) {
4162
4274
  console.error(err);