@diplodoc/cli 4.15.1 → 4.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "author": "Yandex Data UI Team <data-ui@yandex-team.ru>",
4
4
  "description": "Make documentation using yfm-docs in Markdown and HTML formats",
5
5
  "license": "MIT",
6
- "version": "4.15.1",
6
+ "version": "4.16.1",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git@github.com:diplodoc-platform/cli.git"
@@ -15,6 +15,7 @@
15
15
  "files": [
16
16
  "build",
17
17
  "assets",
18
+ "schemas",
18
19
  "src"
19
20
  ],
20
21
  "scripts": {
@@ -62,13 +63,13 @@
62
63
  "ajv": "^8.11.0",
63
64
  "async": "^3.2.4",
64
65
  "axios": "^1.6.7",
65
- "chalk": "4.1.2",
66
+ "chalk": "^4.1.2",
66
67
  "esbuild": "^0.20.0",
67
68
  "glob": "^8.0.3",
68
69
  "html-escaper": "^3.0.3",
69
70
  "husky": "8.0.3",
70
71
  "js-yaml": "4.1.0",
71
- "lint-staged": "13.2.2",
72
+ "lint-staged": "^12.5.0",
72
73
  "lodash": "4.17.21",
73
74
  "mime-types": "2.1.35",
74
75
  "minimatch": "^9.0.3",
@@ -0,0 +1,56 @@
1
+ $schema: 'http://json-schema.org/draft-07/schema#'
2
+ $id: 'https://diplodoc.com/schemas/leading/draft-01/schema#'
3
+ title: Leading page file schema
4
+ type: object
5
+ properties:
6
+ title:
7
+ $ref: '#/definitions/TextItems'
8
+
9
+ description:
10
+ $ref: '#/definitions/TextItems'
11
+
12
+ meta:
13
+ type: object
14
+ properties:
15
+ title:
16
+ $ref: '#/definitions/TextItems'
17
+ description:
18
+ $ref: '#/definitions/TextItems'
19
+ noIndex:
20
+ type: boolean
21
+ additionalProperties: false
22
+
23
+ nav:
24
+ type: object
25
+ properties:
26
+ title:
27
+ $ref: '#/definitions/TextItems'
28
+ additionalProperties: false
29
+
30
+ links:
31
+ type: array
32
+ items:
33
+ type: object
34
+ properties:
35
+ title:
36
+ type: string
37
+ translate: md
38
+ description:
39
+ type: string
40
+ translate: md
41
+ href:
42
+ type: string
43
+ format: url
44
+ additionalProperties: false
45
+
46
+ additionalProperties: false
47
+
48
+ definitions:
49
+ TextItems:
50
+ oneOf:
51
+ - type: string
52
+ - type: array
53
+ items:
54
+ type: string
55
+ translate: md
56
+
@@ -0,0 +1,31 @@
1
+ $schema: 'http://json-schema.org/draft-07/schema#'
2
+ $id: 'https://diplodoc.com/schemas/presets/draft-01/schema#'
3
+ title: Presets file schema
4
+ type: object
5
+ properties:
6
+ default:
7
+ $ref: '#/definitions/preset'
8
+ patternProperties:
9
+ '^[a-zA-Z0-9\.\-_]+$':
10
+ $ref: '#/definitions/preset'
11
+
12
+ definitions:
13
+ preset:
14
+ type: object
15
+ properties:
16
+ i18n:
17
+ type: object
18
+ patternProperties:
19
+ '^[a-zA-Z0-9\.\-_]+$':
20
+ $ref: '#/definitions/property'
21
+ additionalProperties: true
22
+
23
+ property:
24
+ oneOf:
25
+ - type: string
26
+ translate: md
27
+ - type: number
28
+ - type: object
29
+ patternProperties:
30
+ '^[a-zA-Z0-9\.\-_]+$':
31
+ $ref: '#/definitions/property'
@@ -0,0 +1,302 @@
1
+ $schema: 'http://json-schema.org/draft-07/schema#'
2
+ $id: 'https://diplodoc.com/schemas/toc/draft-01/schema#'
3
+ title: Table of content file schema
4
+ type: object
5
+ properties:
6
+ title:
7
+ type: string
8
+ translate: md
9
+ href:
10
+ type: string
11
+ format: url
12
+ stage:
13
+ type: string
14
+ base:
15
+ type: string
16
+ singlePage:
17
+ type: boolean
18
+ when:
19
+ type:
20
+ - string
21
+ - boolean
22
+ navigation:
23
+ $ref: '#/definitions/Navigation'
24
+ items:
25
+ $ref: '#/definitions/TocItems'
26
+
27
+ definitions:
28
+ TocItems:
29
+ type: array
30
+ items:
31
+ $ref: '#/definitions/TocItem'
32
+
33
+ TocItem:
34
+ type: object
35
+ properties:
36
+ name:
37
+ type: string
38
+ translate: md
39
+ expanded:
40
+ type: boolean
41
+ hidden:
42
+ type:
43
+ - boolean
44
+ - string
45
+ items:
46
+ $ref: '#/definitions/TocItems'
47
+ oneOf:
48
+ - $ref: '#/definitions/TocItemWithLink'
49
+ - $ref: '#/definitions/TocItemWithInclude'
50
+
51
+ TocItemWithLink:
52
+ required: ['name']
53
+ properties:
54
+ name:
55
+ type: string
56
+ translate: md
57
+ href:
58
+ type: string
59
+
60
+ TocItemWithInclude:
61
+ required: ['include']
62
+ properties:
63
+ name:
64
+ type: string
65
+ translate: md
66
+ include:
67
+ $ref: '#/definitions/Include'
68
+
69
+ Include:
70
+ type: object
71
+ properties:
72
+ mode:
73
+ type: string
74
+ enum: ['link', 'merge', 'root_merge']
75
+ path:
76
+ type: string
77
+ includers:
78
+ type: array
79
+ items:
80
+ $ref: '#/definitions/Includer'
81
+ additionalProperties: false
82
+
83
+ Includer:
84
+ type: object
85
+ required: ['name']
86
+ properties:
87
+ name:
88
+ type: string
89
+ additionalProperties: true
90
+
91
+ OpenApiIncluder:
92
+ type: object
93
+ required: ['input']
94
+ properties:
95
+ input:
96
+ type: string
97
+ filter:
98
+ $ref: '#/definitions/OpenApiIncluderFilter'
99
+ noindex:
100
+ $ref: '#/definitions/OpenApiIncluderFilter'
101
+ hidden:
102
+ $ref: '#/definitions/OpenApiIncluderFilter'
103
+ sandbox:
104
+ type: object
105
+ properties:
106
+ tabName:
107
+ type: string
108
+ translate: text
109
+ host:
110
+ type: string
111
+ format: url
112
+ leadingPage:
113
+ type: object
114
+ properties:
115
+ name:
116
+ type: string
117
+ mode:
118
+ type: string
119
+ enum: ['section', 'leaf']
120
+ spec:
121
+ type: object
122
+ properties:
123
+ renderMode:
124
+ type: string
125
+ enum: ['inline', 'hidden']
126
+
127
+ OpenApiIncluderFilter:
128
+ type: object
129
+ properties:
130
+ endpoint:
131
+ type: string
132
+ tag:
133
+ type: string
134
+
135
+ Navigation:
136
+ type: object
137
+ properties:
138
+ logo:
139
+ $ref: '#/definitions/NavigationLogo'
140
+ header:
141
+ $ref: '#/definitions/NavigationHeader'
142
+
143
+ NavigationLogo:
144
+ type: object
145
+ properties:
146
+ text:
147
+ type: string
148
+ url:
149
+ type: string
150
+ format: url
151
+ urlTitle:
152
+ type: string
153
+ icon:
154
+ type: string
155
+ format: url
156
+ dark:
157
+ $ref: '#/definitions/NavigationLogo'
158
+ light:
159
+ $ref: '#/definitions/NavigationLogo'
160
+
161
+ NavigationHeader:
162
+ type: object
163
+ properties:
164
+ leftItems:
165
+ $ref: '#/definitions/NavigationItems'
166
+ rightItems:
167
+ $ref: '#/definitions/NavigationItems'
168
+ iconSize:
169
+ type: number
170
+
171
+ NavigationItems:
172
+ type: array
173
+ items:
174
+ $ref: '#/definitions/NavigationItem'
175
+
176
+ NavigationItem:
177
+ type: object
178
+ required: ['type']
179
+ properties:
180
+ type:
181
+ type: string
182
+ allOf:
183
+ - $ref: '#/definitions/NavigationBaseItem'
184
+ - oneOf:
185
+ - $ref: '#/definitions/NavigationLinkItem'
186
+ - $ref: '#/definitions/NavigationButtonItem'
187
+ - $ref: '#/definitions/NavigationDropdownItem'
188
+ - $ref: '#/definitions/NavigationControlsItem'
189
+
190
+ NavigationBaseItem:
191
+ type: object
192
+ properties:
193
+ text:
194
+ type: string
195
+ translate: md
196
+ url:
197
+ type: string
198
+ format: url
199
+ icon:
200
+ type: string
201
+ format: url
202
+ iconSize:
203
+ type: number
204
+
205
+ NavigationLinkItem:
206
+ type: object
207
+ properties:
208
+ type:
209
+ type: string
210
+ pattern: '^link$'
211
+ target:
212
+ $ref: '#/definitions/NavigationLinkTarget'
213
+ arrow:
214
+ type: boolean
215
+ required: ['type', 'text']
216
+
217
+ NavigationButtonItem:
218
+ properties:
219
+ type:
220
+ type: string
221
+ pattern: '^button$'
222
+ urlTitle:
223
+ type: string
224
+ translate: md
225
+ primary:
226
+ type: boolean
227
+ size:
228
+ type: string
229
+ theme:
230
+ type: string
231
+ img:
232
+ oneOf:
233
+ - type: string
234
+ - type: object
235
+ required: ['data']
236
+ properties:
237
+ data:
238
+ type: string
239
+ position:
240
+ type: string
241
+ enum: ['left', 'right']
242
+ alt:
243
+ type: string
244
+ translate: md
245
+ analyticsEvents:
246
+ oneOf:
247
+ - $ref: '#/definitions/NavigationAnalyticsEvent'
248
+ - type: array
249
+ items:
250
+ $ref: '#/definitions/NavigationAnalyticsEvent'
251
+ target:
252
+ $ref: '#/definitions/NavigationLinkTarget'
253
+ width:
254
+ type: string
255
+ enum: ['auto', 'max']
256
+ required: ['type', 'text', 'url']
257
+
258
+ NavigationDropdownItem:
259
+ type: object
260
+ properties:
261
+ type:
262
+ type: string
263
+ pattern: '^dropdown$'
264
+ items:
265
+ type: array
266
+ items:
267
+ $ref: '#/definitions/NavigationLinkItem'
268
+ required: ['type', 'items']
269
+
270
+ NavigationControlsItem:
271
+ type: object
272
+ properties:
273
+ type:
274
+ type: string
275
+ pattern: '^controls$'
276
+ required: ['type']
277
+
278
+ NavigationLinkTarget:
279
+ type: string
280
+ enum: ['_self', '_blank', '_parent', '_top']
281
+
282
+ NavigationAnalyticsEvent:
283
+ type: object
284
+ required: ['name']
285
+ properties:
286
+ name:
287
+ type: string
288
+ type:
289
+ type: string
290
+ counters:
291
+ type: object
292
+ properties:
293
+ include:
294
+ type: array
295
+ items:
296
+ type: string
297
+ exclude:
298
+ type: array
299
+ items:
300
+ type: string
301
+ context:
302
+ type: string
@@ -100,15 +100,7 @@ function pipeline(input: string, output: string, {useSource}: ComposeOptions) {
100
100
  loadFile<string>(join(input, file.xliff)),
101
101
  ]);
102
102
 
103
- let schemas;
104
- if (['.yaml', '.json'].includes(file.ext)) {
105
- schemas = resolveSchemas(file.path);
106
-
107
- if (!schemas) {
108
- return;
109
- }
110
- }
111
-
103
+ const schemas = await resolveSchemas(file.path);
112
104
  const result = _compose(skeleton, xliff, {useSource, schemas});
113
105
  const filePath = join(output, file.path);
114
106
 
@@ -121,24 +121,21 @@ function pipeline(params: PipelineParameters) {
121
121
  const xliffPath = join(outputRoot, outputPath + '.xliff');
122
122
  const skeletonPath = join(outputRoot, outputPath + '.skl');
123
123
 
124
- let schemas;
125
- if (['.yaml', '.json'].includes(ext)) {
126
- schemas = resolveSchemas(path);
127
-
128
- if (!schemas) {
129
- return;
130
- }
131
- }
132
-
124
+ const schemas = await resolveSchemas(path);
133
125
  const content = await loadFile(inputPath);
134
126
 
135
127
  await mkdir(dirname(xliffPath), {recursive: true});
136
128
 
137
- const {xliff, skeleton} = _extract(content, {
129
+ const {xliff, skeleton, units} = _extract(content, {
138
130
  source,
139
131
  target,
132
+ schemas,
140
133
  });
141
134
 
135
+ if (!units.length) {
136
+ return;
137
+ }
138
+
142
139
  await Promise.all([dumpFile(skeletonPath, skeleton), dumpFile(xliffPath, xliff)]);
143
140
  };
144
141
  }
@@ -22,6 +22,7 @@ import {
22
22
  extract,
23
23
  loadFile,
24
24
  normalizeParams,
25
+ resolveSchemas,
25
26
  } from './utils';
26
27
 
27
28
  const REQUESTS_LIMIT = 20;
@@ -262,6 +263,7 @@ function translator(params: TranslatorParams, split: Split) {
262
263
  return;
263
264
  }
264
265
 
266
+ const schemas = await resolveSchemas(path);
265
267
  const {units, skeleton} = extract(content, {
266
268
  compact: true,
267
269
  source: {
@@ -272,6 +274,7 @@ function translator(params: TranslatorParams, split: Split) {
272
274
  language: targetLanguage,
273
275
  locale: 'US',
274
276
  },
277
+ schemas,
275
278
  });
276
279
 
277
280
  if (!units.length) {
@@ -280,7 +283,7 @@ function translator(params: TranslatorParams, split: Split) {
280
283
  }
281
284
 
282
285
  const parts = await split(path, units);
283
- const composed = compose(skeleton, parts, {useSource: true});
286
+ const composed = compose(skeleton, parts, {useSource: true, schemas});
284
287
 
285
288
  await dumpFile(outputPath, composed);
286
289
  };
@@ -1,17 +1,30 @@
1
1
  import {JSONValue, resolveRefs} from '@diplodoc/translation';
2
- import {extname} from 'path';
3
2
  import {dump, load} from 'js-yaml';
4
3
  import {readFile, writeFile} from 'fs/promises';
5
4
 
5
+ function last<T>(array: T[]): T | undefined {
6
+ return array[array.length - 1];
7
+ }
8
+
9
+ function ext(path: string) {
10
+ const parts = path.split('.');
11
+
12
+ if (last(parts) === 'skl') {
13
+ parts.pop();
14
+ }
15
+
16
+ return last(parts);
17
+ }
18
+
6
19
  function parseFile(text: string, path: string): JSONValue | string {
7
20
  if (typeof text !== 'string') {
8
21
  return text;
9
22
  }
10
23
 
11
- switch (extname(path)) {
12
- case '.yaml':
24
+ switch (ext(path)) {
25
+ case 'yaml':
13
26
  return load(text) as object;
14
- case '.json':
27
+ case 'json':
15
28
  return JSON.parse(text);
16
29
  default:
17
30
  return text;
@@ -23,22 +36,22 @@ function stringifyFile(content: JSONValue | string, path: string): string {
23
36
  return content;
24
37
  }
25
38
 
26
- switch (extname(path)) {
27
- case '.yaml':
39
+ switch (ext(path)) {
40
+ case 'yaml':
28
41
  return dump(content);
29
- case '.json':
42
+ case 'json':
30
43
  return JSON.stringify(content);
31
44
  default:
32
45
  return content as unknown as string;
33
46
  }
34
47
  }
35
48
 
36
- export async function loadFile<T = string | JSONValue>(path: string): Promise<T> {
49
+ export async function loadFile<T = string | JSONValue>(path: string, resolve = true): Promise<T> {
37
50
  const text = await readFile(path, 'utf8');
38
51
 
39
52
  let content = parseFile(text, path);
40
53
 
41
- if (content && typeof content === 'object') {
54
+ if (content && typeof content === 'object' && resolve) {
42
55
  content = await resolveRefs(content, path, parseFile);
43
56
  }
44
57
 
@@ -50,3 +63,27 @@ export async function dumpFile(path: string, content: string | JSONValue) {
50
63
 
51
64
  await writeFile(path, text, 'utf8');
52
65
  }
66
+
67
+ /**
68
+ * Takes toc schema if file matched as toc.
69
+ * Takes leading schema if file matched as leading page.
70
+ * Takes presets schema if file matched as presets.
71
+ * Any way translation inner logic will search `$schema` attribute with high priority.
72
+ * If `$schema` attribute not found anc precise schema not resolved,
73
+ * we think that current yaml is a part of complex toc.yaml
74
+ */
75
+ export async function resolveSchemas(path: string) {
76
+ if (path.endsWith('toc.yaml')) {
77
+ return [await loadFile('schemas/toc-schema.yaml', false)];
78
+ }
79
+
80
+ if (path.endsWith('index.yaml')) {
81
+ return [await loadFile('schemas/leading-schema.yaml', false)];
82
+ }
83
+
84
+ if (path.endsWith('presets.yaml')) {
85
+ return [await loadFile('schemas/presets-schema.yaml', false)];
86
+ }
87
+
88
+ return [await loadFile('schemas/toc-schema.yaml', false)];
89
+ }
@@ -3,7 +3,7 @@ import {basename, dirname, extname, resolve} from 'path';
3
3
  import {readFileSync} from 'node:fs';
4
4
  import glob from 'glob';
5
5
 
6
- export {dumpFile, loadFile} from './fs';
6
+ export {dumpFile, loadFile, resolveSchemas} from './fs';
7
7
  export {extract, compose} from './translate';
8
8
  export {TranslateError, LimitExceed, RequestError, AuthError} from './errors';
9
9
 
@@ -138,10 +138,6 @@ function normalizeInput(params: TranslateArgs, language: string, exts: string[])
138
138
  return {input, files};
139
139
  }
140
140
 
141
- export function resolveSchemas(_path: string) {
142
- return null;
143
- }
144
-
145
141
  export class Defer<T = string> {
146
142
  resolve!: (text: T) => void;
147
143