@diplodoc/cli-tests 0.0.0-rc-err-count-202505291233 → 0.0.0-rc-toc-translation-202506181609

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.
Files changed (53) hide show
  1. package/e2e/__snapshots__/include-toc.test.ts.snap +98 -106
  2. package/e2e/__snapshots__/load-custom-resources.spec.ts.snap +66 -56
  3. package/e2e/__snapshots__/metadata.spec.ts.snap +19 -14
  4. package/e2e/__snapshots__/plugin-corner-cases.spec.ts.snap +0 -0
  5. package/e2e/__snapshots__/regression.test.ts.snap +764 -760
  6. package/e2e/__snapshots__/restricted-access.test.ts.snap +234 -0
  7. package/e2e/__snapshots__/rtl.spec.ts.snap +57 -47
  8. package/e2e/__snapshots__/translation.spec.ts.snap +1296 -110
  9. package/e2e/errors.spec.ts +37 -0
  10. package/e2e/restricted-access.test.ts +21 -0
  11. package/e2e/translation.spec.ts +14 -3
  12. package/fixtures/cliAdapter.ts +39 -20
  13. package/fixtures/runners/binary.ts +21 -3
  14. package/fixtures/runners/index.ts +3 -1
  15. package/fixtures/runners/source.ts +5 -5
  16. package/fixtures/runners/types.ts +7 -1
  17. package/fixtures/utils/file.ts +3 -3
  18. package/fixtures/utils/test.ts +6 -1
  19. package/mocks/errors/unreachable-link/input/exists.md +1 -0
  20. package/mocks/errors/unreachable-link/input/index.md +2 -0
  21. package/mocks/errors/unreachable-link/input/toc.yaml +1 -0
  22. package/mocks/regression/input/1.md +0 -4
  23. package/mocks/regression/input/_assets/5_1.png +0 -0
  24. package/mocks/regression/input/images.md +2 -0
  25. package/mocks/regression/input/includes.md +1 -0
  26. package/mocks/restricted-access/test1/input/index.md +0 -0
  27. package/mocks/restricted-access/test1/input/plugins/index.md +0 -0
  28. package/mocks/restricted-access/test1/input/plugins/index2.md +0 -0
  29. package/mocks/restricted-access/test1/input/plugins/index3.md +0 -0
  30. package/mocks/restricted-access/test1/input/plugins/index4.md +4 -0
  31. package/mocks/restricted-access/test1/input/toc.yaml +28 -0
  32. package/mocks/restricted-access/test2/input/index.md +0 -0
  33. package/mocks/restricted-access/test2/input/plugins/index.md +0 -0
  34. package/mocks/restricted-access/test2/input/project/index.md +0 -0
  35. package/mocks/restricted-access/test2/input/toc.yaml +21 -0
  36. package/mocks/restricted-access/test3/input/a1.md +1 -0
  37. package/mocks/restricted-access/test3/input/folder1/a1.md +1 -0
  38. package/mocks/restricted-access/test3/input/folder1/folder2/a1.md +1 -0
  39. package/mocks/restricted-access/test3/input/folder1/folder2/toc.yaml +8 -0
  40. package/mocks/restricted-access/test3/input/folder1/toc.yaml +10 -0
  41. package/mocks/restricted-access/test3/input/index.md +0 -0
  42. package/mocks/restricted-access/test3/input/toc.yaml +16 -0
  43. package/mocks/translation/dir-files/input/.yfm +5 -0
  44. package/mocks/translation/dir-files/input/ru/aboba.md +1 -3
  45. package/mocks/translation/dir-files/input/ru/nested/a1.md +3 -0
  46. package/mocks/translation/dir-files/input/ru/nested/folder1/a1.md +3 -0
  47. package/mocks/translation/dir-files/input/ru/nested/folder1/toc-i.yaml +3 -0
  48. package/mocks/translation/dir-files/input/ru/nested/toc.yaml +1 -0
  49. package/mocks/translation/dir-files/input/ru/no-var-page.md +3 -0
  50. package/mocks/translation/dir-files/input/ru/to-be-excluded.md +1 -0
  51. package/mocks/translation/dir-files/input/ru/toc.yaml +7 -1
  52. package/package.json +4 -3
  53. package/vitest.config.ts +1 -2
@@ -0,0 +1,37 @@
1
+ import type {Report} from '../fixtures/runners/types';
2
+
3
+ import {describe, expect, it} from 'vitest';
4
+ import {TestAdapter, getTestPaths} from '../fixtures';
5
+
6
+ type TestResult = {
7
+ md: Report;
8
+ html: Report;
9
+ }
10
+
11
+ function test(path: string, expect: Function) {
12
+ it(path, async () => {
13
+ const {inputPath, outputPath} = getTestPaths(path);
14
+
15
+ const md = await TestAdapter.build.run(inputPath, outputPath, ['-j2', '-f', 'md']);
16
+ const html = await TestAdapter.build.run(outputPath, outputPath + '-html', ['-j2', '-f', 'html']);
17
+
18
+ return expect({md, html});
19
+ });
20
+ }
21
+
22
+ describe('Errors', () => {
23
+ test('mocks/errors/unreachable-link', ({html}: TestResult) => {
24
+ expectErrors(html, [
25
+ 'ERR index.md: 1: YFM003 / unreachable-link Link is unreachable [Context: "[Unreachable link: "exists.html"][existing file](./exists.md)"]',
26
+ 'ERR index.md: 2: YFM003 / unreachable-link Link is unreachable [Context: "[Unreachable link: "missed.html"][missed file](./missed.md)"]'
27
+ ]);
28
+ });
29
+ });
30
+
31
+ function expectErrors(report: Report, errors: string[]) {
32
+ expect(report.code).toEqual(1);
33
+
34
+ for (const error of errors) {
35
+ expect(report.errors).toContain(error);
36
+ }
37
+ }
@@ -0,0 +1,21 @@
1
+ import {describe, test} from 'vitest';
2
+ import {TestAdapter, compareDirectories, getTestPaths} from '../fixtures';
3
+
4
+ const generateFilesYamlTestTemplate = (
5
+ testTitle: string,
6
+ testRootPath: string
7
+ ) => {
8
+ test(testTitle, async () => {
9
+ const {inputPath, outputPath} = getTestPaths(testRootPath);
10
+ await TestAdapter.testBuildPass(inputPath, outputPath, {md2md:true});
11
+ await compareDirectories(outputPath);
12
+ });
13
+ };
14
+
15
+ describe('Restricted access', () => {
16
+ generateFilesYamlTestTemplate('Simple restricted access', 'mocks/restricted-access/test1');
17
+
18
+ generateFilesYamlTestTemplate('Nested restricted access', 'mocks/restricted-access/test2');
19
+
20
+ generateFilesYamlTestTemplate('Nested toc restricted access', 'mocks/restricted-access/test3');
21
+ });
@@ -6,12 +6,12 @@ const generateMapTestTemplate = (
6
6
  testRootPath: string,
7
7
  args: TranslateRunArgs,
8
8
  ) => {
9
- test.skip(testTitle, async () => {
9
+ test(testTitle, async () => {
10
10
  const {inputPath, outputPath} = getTestPaths(testRootPath);
11
11
 
12
12
  await TestAdapter.testTranslatePass(inputPath, outputPath, args);
13
13
 
14
- await compareDirectories(outputPath, true);
14
+ await compareDirectories(outputPath);
15
15
  });
16
16
  };
17
17
 
@@ -43,7 +43,18 @@ describe('Translate command', () => {
43
43
  subcommand: 'extract',
44
44
  source: 'ru-RU',
45
45
  target: 'es-ES',
46
- additionalArgs: '--exclude ru/_no-translate/*.md',
46
+ additionalArgs: '--exclude ru/to-be-excluded.md',
47
+ },
48
+ );
49
+
50
+ generateMapTestTemplate(
51
+ 'filter files on extract with --strict-vars options',
52
+ 'mocks/translation/dir-files',
53
+ {
54
+ subcommand: 'extract',
55
+ source: 'ru-RU',
56
+ target: 'es-ES',
57
+ additionalArgs: '--strict-vars',
47
58
  },
48
59
  );
49
60
 
@@ -14,8 +14,30 @@ export interface TranslateRunArgs {
14
14
  additionalArgs?: string;
15
15
  }
16
16
 
17
+ class Build {
18
+ private readonly runner: Runner;
19
+
20
+ constructor(runner: Runner) {
21
+ this.runner = runner;
22
+ }
23
+
24
+ run(input: string, output: string, args: string[]) {
25
+ return this.runner.runYfmDocs([
26
+ '--input',
27
+ input,
28
+ '--output',
29
+ output,
30
+ '--quiet',
31
+ '--allowHTML',
32
+ ...args,
33
+ ]);
34
+ }
35
+ }
36
+
17
37
  export class CliTestAdapter {
18
- private readonly runner: Runner = createRunner();
38
+ readonly runner: Runner = createRunner();
39
+
40
+ readonly build = new Build(this.runner);
19
41
 
20
42
  async testBuildPass(
21
43
  inputPath: string,
@@ -23,30 +45,27 @@ export class CliTestAdapter {
23
45
  {md2md = true, md2html = true, args = ''}: BuildRunArgs = {},
24
46
  ): Promise<void> {
25
47
  await cleanupDirectory(outputPath);
48
+ await cleanupDirectory(`${outputPath}-md`);
49
+ await cleanupDirectory(`${outputPath}-html`);
26
50
 
27
- const baseArgs = [
28
- '--input',
29
- inputPath,
30
- '--quiet',
31
- '--allowHTML',
32
- ...args.split(' ').filter(Boolean),
33
- ];
51
+ const baseArgs = args.split(' ').filter(Boolean);
52
+
53
+ const tasks = [];
34
54
 
35
55
  if (md2md && md2html) {
36
- await cleanupDirectory(`${outputPath}-html`);
37
-
38
- await this.runner.runYfmDocs([...baseArgs, '--output', outputPath, '-f', 'md']);
39
- await this.runner.runYfmDocs([
40
- ...baseArgs,
41
- '--output',
42
- `${outputPath}-html`,
43
- '-f',
44
- 'html',
45
- ]);
56
+ tasks.push(() => this.build.run(inputPath, outputPath,[...baseArgs, '-f', 'md']));
57
+ tasks.push(() => this.build.run(inputPath, `${outputPath}-html`, [...baseArgs, '-f', 'html']));
46
58
  } else if (md2md) {
47
- await this.runner.runYfmDocs([...baseArgs, '--output', outputPath, '-f', 'md']);
59
+ tasks.push(() => this.build.run(inputPath, outputPath, [...baseArgs, '-f', 'md']));
48
60
  } else {
49
- await this.runner.runYfmDocs([...baseArgs, '--output', outputPath]);
61
+ tasks.push(() => this.build.run(inputPath, outputPath, [...baseArgs, '-f', 'html']));
62
+ }
63
+
64
+ for (const task of tasks) {
65
+ const report = await task();
66
+ if (report.code > 0) {
67
+ throw report;
68
+ }
50
69
  }
51
70
  }
52
71
 
@@ -9,9 +9,27 @@ export class BinaryRunner implements Runner {
9
9
  }
10
10
 
11
11
  async runYfmDocs(argv: string[]) {
12
- const {all} = await execa(this.binaryPath, argv, {all: true});
12
+ const {stderr, exitCode} = await execa(this.binaryPath, argv, {all: true, reject: false});
13
+ const report = {
14
+ code: exitCode || 0,
15
+ warns: fillLog(/^WARN/, stderr),
16
+ errors: fillLog(/^ERR/, stderr),
17
+ };
13
18
 
14
- // eslint-disable-next-line no-console
15
- console.log(all);
19
+ const restLog = fillLog(/^(?!INFO|WARN|ERR)/, stderr);
20
+ if (restLog.length) {
21
+ for (const line of restLog) {
22
+ console.log(line);
23
+ }
24
+ }
25
+
26
+ return report;
16
27
  }
17
28
  }
29
+
30
+ function fillLog(filter: RegExp, source: string) {
31
+ return source.split('\n')
32
+ .filter((line) => line.match(filter))
33
+ .map((line) => line.trim())
34
+ .filter(Boolean);
35
+ }
@@ -1,3 +1,5 @@
1
+ import {resolve} from 'node:path';
2
+
1
3
  import {SourceRunner} from './source';
2
4
  import {BinaryRunner} from './binary';
3
5
  import {Runner} from './types';
@@ -5,7 +7,7 @@ import {Runner} from './types';
5
7
  export {Runner};
6
8
 
7
9
  export function createRunner(): Runner {
8
- const binaryPath = process.env.DIPLODOC_BINARY_PATH;
10
+ const binaryPath = process.env.DIPLODOC_BINARY_PATH || resolve(__dirname, '../../../build/index.js');
9
11
 
10
12
  if (binaryPath) {
11
13
  return new BinaryRunner(binaryPath);
@@ -1,15 +1,15 @@
1
+ import type {Report} from './types';
2
+
1
3
  export class SourceRunner {
2
4
  readonly MODULE_PATH = require.resolve('../../../');
3
5
 
4
- async runYfmDocs(argv: string[]): Promise<void> {
6
+ async runYfmDocs(argv: string[]) {
5
7
  const {run} = await import(this.MODULE_PATH);
6
8
 
7
9
  const baseArgs = ['node', this.MODULE_PATH, ...argv];
8
10
 
9
- const exitCode = await run(baseArgs);
11
+ const report = await run(baseArgs) as Report;
10
12
 
11
- if (exitCode !== 0) {
12
- throw new Error(`CLI exited with code ${exitCode}`);
13
- }
13
+ return report;
14
14
  }
15
15
  }
@@ -1,4 +1,10 @@
1
+ export type Report = {
2
+ code: number;
3
+ warns: string[];
4
+ errors: string[];
5
+ }
6
+
1
7
  export interface Runner {
2
- runYfmDocs(argv: string[]): Promise<void>;
8
+ runYfmDocs(argv: string[]): Promise<Report>;
3
9
  }
4
10
 
@@ -1,7 +1,7 @@
1
1
  import {readFileSync} from 'node:fs';
2
2
  import {join, resolve} from 'node:path';
3
3
  import {glob} from 'glob';
4
- import {bundleless, platformless} from './test';
4
+ import {bundleless, hashless, platformless} from './test';
5
5
  import {expect} from 'vitest';
6
6
  import {$} from 'execa';
7
7
 
@@ -23,12 +23,12 @@ export async function compareDirectories(outputPath: string, ignoreFileContent =
23
23
  })
24
24
  ).sort();
25
25
 
26
- expect(bundleless(JSON.stringify(filesFromOutput, null, 2))).toMatchSnapshot('filelist');
26
+ expect(hashless(bundleless(JSON.stringify(filesFromOutput, null, 2)))).toMatchSnapshot('filelist');
27
27
 
28
28
  if (!ignoreFileContent) {
29
29
  filesFromOutput.filter(uselessFile).forEach((filePath) => {
30
30
  const content = getFileContent(resolve(outputPath, filePath));
31
- expect(content).toMatchSnapshot(filePath);
31
+ expect(content).toMatchSnapshot();
32
32
  });
33
33
  }
34
34
  }
@@ -1,13 +1,18 @@
1
1
  import {readFileSync} from 'node:fs';
2
2
 
3
3
  export function platformless(text: string): string {
4
- return text
4
+ return hashless(text)
5
5
  .replace(/\r\n/g, '\n')
6
6
  .replace(/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/g, 'UUID')
7
7
  .replace(/(content"?[:=]{1}[" ]{1}Diplodoc.*? )v\d+\.\d+\.\d+(?:-[\w-]+)?/g, `$1vDIPLODOC-VERSION`)
8
8
  .replace(/(\\(?![/"'])){1,2}/g, '/');
9
9
  }
10
10
 
11
+ export function hashless(text: string): string {
12
+ return text
13
+ .replace(/-[a-z0-9]{12}\./g, '-hash.')
14
+ }
15
+
11
16
  export function bundleless(text: string): string {
12
17
  const assets = require('@diplodoc/client/manifest') as Record<string, Record<string, string[]>>;
13
18
 
@@ -0,0 +1 @@
1
+ File exists but not attached to toc
@@ -0,0 +1,2 @@
1
+ [existing file](./exists.md)
2
+ [missed file](./missed.md)
@@ -0,0 +1 @@
1
+ href: index.md
@@ -24,10 +24,6 @@ not_var{{skip()}}
24
24
 
25
25
  [](./latex.md)
26
26
 
27
- [nowhere-link](./nowhere-link.md)
28
-
29
27
  [noext-link](./includes)
30
28
 
31
29
  {% include [user](includes/user.md) %}
32
-
33
- Forbibben text before {% include [user](includes/user.md) %}
File without changes
@@ -7,3 +7,5 @@
7
7
  ![with trailing comment](_assets/3.png)<!-- comment -->
8
8
 
9
9
  <!-- ![commented](_assets/4.png) -->
10
+
11
+ ![with backslash](_assets/5\_1.png)
@@ -4,4 +4,5 @@ Text
4
4
 
5
5
  {% include [test](includes/test.md) %}
6
6
 
7
+ <!--{% include [For includes/deep.md](includes/deep.md) %}-->
7
8
  {% include [For includes/deep.md](includes/deep.md) %}
File without changes
@@ -0,0 +1,4 @@
1
+ ---
2
+ restricted-access:
3
+ - - customInFile
4
+ ---
@@ -0,0 +1,28 @@
1
+ title: Yandex Flavored Markdown
2
+ items:
3
+ - name: Yandex Flavored Markdown
4
+ href: index.md
5
+ restricted-access: admin
6
+ - name: Plugins
7
+ items:
8
+ - name: Overview
9
+ href: plugins/index.md
10
+ restricted-access:
11
+ - admin
12
+ - name: Plugins 2
13
+ restricted-access: admin
14
+ items:
15
+ - name: Overview 2
16
+ href: plugins/index2.md
17
+ restricted-access:
18
+ - admin
19
+ - user
20
+ - name: Overview 3
21
+ href: plugins/index3.md
22
+ restricted-access:
23
+ - admin
24
+ - name: Overview 4
25
+ href: plugins/index4.md
26
+ restricted-access:
27
+ - admin
28
+
File without changes
@@ -0,0 +1,21 @@
1
+ title: Yandex Flavored Markdown
2
+ items:
3
+ - name: Plugins
4
+ restricted-access:
5
+ - admin
6
+ - manager
7
+ items:
8
+ - name: Overview
9
+ href: plugins/index.md
10
+ restricted-access:
11
+ - userA
12
+ - userB
13
+ - name: Organizing a YFM project
14
+ items:
15
+ - name: Overview
16
+ href: project/index.md
17
+ restricted-access:
18
+ - userA
19
+ - userB
20
+
21
+
@@ -0,0 +1 @@
1
+ This is the /a1.md file content.
@@ -0,0 +1 @@
1
+ This is the /folder1/a1.md file content.
@@ -0,0 +1 @@
1
+ This is the /folder1/folder1/a1.md file content.
@@ -0,0 +1,8 @@
1
+ items:
2
+ - name: A1
3
+ href: a1.md
4
+ restricted-access:
5
+ - userAtoc3
6
+ - userBtoc3
7
+
8
+
@@ -0,0 +1,10 @@
1
+ items:
2
+ - name: A1
3
+ href: a1.md
4
+ restricted-access:
5
+ - userAtoc2
6
+ - userBtoc2
7
+ - name: folder1
8
+ include:
9
+ mode: link
10
+ path: folder2/toc.yaml
File without changes
@@ -0,0 +1,16 @@
1
+ items:
2
+ - name: A1
3
+ href: a1.md
4
+ - name: folder1
5
+ restricted-access:
6
+ - userA
7
+ - userB
8
+ include:
9
+ mode: link
10
+ path: folder1/toc.yaml
11
+
12
+
13
+
14
+
15
+
16
+
@@ -0,0 +1,5 @@
1
+ translate:
2
+ extract:
3
+ vars:
4
+ test: prod
5
+ skip: dev
@@ -2,6 +2,4 @@
2
2
 
3
3
  [ссылка на файл не в toc.yaml](./aboba-not-in-toc.md)
4
4
 
5
- {% include [Описание](./_includes/test.md) %}
6
-
7
-
5
+ {% include [Описание](./_includes/test.md) %}
@@ -0,0 +1,3 @@
1
+ ## Included A1
2
+
3
+ TEST
@@ -0,0 +1,3 @@
1
+ ## Included A1
2
+
3
+ TEST
@@ -0,0 +1,3 @@
1
+ items:
2
+ - name: A1
3
+ href: a1.md
@@ -3,6 +3,7 @@ href: index.yaml
3
3
  items:
4
4
  - name: API Yandex Cloud
5
5
  href: index.yaml
6
+ - include: {mode: merge, path: folder1/toc-i.yaml}
6
7
  - name: Yandex Flavored Markdown
7
8
  href: index-yfm.md
8
9
  items:
@@ -0,0 +1,3 @@
1
+ ## No var page
2
+
3
+ This page might be translated or not. Depends on --strict-vars option.
@@ -0,0 +1 @@
1
+ ## Excluded title
@@ -4,4 +4,10 @@ items:
4
4
  - name: Aboba
5
5
  href: aboba.md
6
6
  - name: Не переводить
7
- href: _no-translate/exclude.md
7
+ when: skip == 'prod'
8
+ href: _no-translate/exclude.md
9
+ - name: Нет переменной в vars
10
+ when: novar == 'test'
11
+ href: no-var-page.md
12
+ - name: exclude-test
13
+ href: to-be-excluded.md
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diplodoc/cli-tests",
3
- "version": "0.0.0-rc-err-count-202505291233",
3
+ "version": "0.0.0-rc-toc-translation-202506181609",
4
4
  "bin": {
5
5
  "diplodoc-cli-test": "bin.mjs"
6
6
  },
@@ -17,7 +17,8 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "build": "false",
20
- "test": "vitest run"
20
+ "test": "vitest run",
21
+ "test:update": "vitest -u"
21
22
  },
22
23
  "publishConfig": {
23
24
  "access": "public"
@@ -26,7 +27,7 @@
26
27
  "@diplodoc/cli": "file:.."
27
28
  },
28
29
  "dependencies": {
29
- "@diplodoc/client": "^3.3.1",
30
+ "@diplodoc/client": "^3.6.3",
30
31
  "@types/node": "18.x",
31
32
  "@vitest/coverage-istanbul": "^3.1.1",
32
33
  "@vitest/coverage-v8": "^3.1.1",
package/vitest.config.ts CHANGED
@@ -17,10 +17,9 @@ export default defineConfig({
17
17
  environment: 'node',
18
18
  include: [
19
19
  'e2e/**/*.{test,spec}.ts',
20
- 'units/**/*.{test,spec}.ts',
21
20
  ...resolvedTestPaths.map((path) => `${path}/**/*.{test,spec}.ts`),
22
21
  ],
23
- exclude: ['node_modules', 'dist'],
22
+ exclude: ['node_modules'],
24
23
  coverage: {
25
24
  enabled: false,
26
25
  },