@openpkg-ts/cli 0.2.3 → 0.3.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/README.md +133 -0
- package/dist/bin/openpkg.js +701 -0
- package/dist/shared/chunk-1dqs11h6.js +20 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/{index.js → src/index.js} +2 -0
- package/package.json +9 -3
- package/CHANGELOG.md +0 -32
- package/bin/openpkg.ts +0 -61
- package/dist/index.d.ts +0 -2
- package/src/commands/diff.ts +0 -175
- package/src/commands/docs.ts +0 -125
- package/src/commands/snapshot.ts +0 -122
- package/src/index.ts +0 -2
- package/test/diff.test.ts +0 -336
- package/test/docs.test.ts +0 -599
- package/test/get.test.ts +0 -413
- package/test/spec.test.ts +0 -469
- package/tsconfig.json +0 -15
package/test/docs.test.ts
DELETED
|
@@ -1,599 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, test } from 'bun:test';
|
|
2
|
-
import * as fs from 'node:fs';
|
|
3
|
-
import * as os from 'node:os';
|
|
4
|
-
import * as path from 'node:path';
|
|
5
|
-
import {
|
|
6
|
-
createDocs,
|
|
7
|
-
exportToMarkdown,
|
|
8
|
-
loadSpec,
|
|
9
|
-
type SimplifiedExport,
|
|
10
|
-
type SimplifiedSpec,
|
|
11
|
-
toHTML,
|
|
12
|
-
toJSON,
|
|
13
|
-
toJSONString,
|
|
14
|
-
toMarkdown,
|
|
15
|
-
} from '@openpkg-ts/sdk';
|
|
16
|
-
import type { OpenPkg } from '@openpkg-ts/spec';
|
|
17
|
-
|
|
18
|
-
// Test fixture spec
|
|
19
|
-
const testSpec: OpenPkg = {
|
|
20
|
-
openpkg: '0.4.0',
|
|
21
|
-
meta: {
|
|
22
|
-
name: 'test-package',
|
|
23
|
-
version: '1.0.0',
|
|
24
|
-
description: 'A test package for docs generation',
|
|
25
|
-
},
|
|
26
|
-
exports: [
|
|
27
|
-
{
|
|
28
|
-
id: 'createClient',
|
|
29
|
-
name: 'createClient',
|
|
30
|
-
kind: 'function',
|
|
31
|
-
description: 'Creates a new API client',
|
|
32
|
-
signatures: [
|
|
33
|
-
{
|
|
34
|
-
parameters: [
|
|
35
|
-
{
|
|
36
|
-
name: 'config',
|
|
37
|
-
schema: { type: 'object', properties: { baseUrl: { type: 'string' } } },
|
|
38
|
-
description: 'Client configuration',
|
|
39
|
-
required: true,
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
returns: {
|
|
43
|
-
schema: { $ref: '#/types/Client' },
|
|
44
|
-
description: 'The configured client instance',
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
|
-
examples: [
|
|
49
|
-
{
|
|
50
|
-
code: 'const client = createClient({ baseUrl: "https://api.example.com" });',
|
|
51
|
-
title: 'Basic Usage',
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
id: 'Config',
|
|
57
|
-
name: 'Config',
|
|
58
|
-
kind: 'interface',
|
|
59
|
-
description: 'Configuration interface',
|
|
60
|
-
members: [
|
|
61
|
-
{
|
|
62
|
-
name: 'baseUrl',
|
|
63
|
-
kind: 'property',
|
|
64
|
-
schema: { type: 'string' },
|
|
65
|
-
description: 'Base URL for API requests',
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
name: 'timeout',
|
|
69
|
-
kind: 'property',
|
|
70
|
-
schema: { type: 'number' },
|
|
71
|
-
description: 'Request timeout in milliseconds',
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
id: 'ApiClient',
|
|
77
|
-
name: 'ApiClient',
|
|
78
|
-
kind: 'class',
|
|
79
|
-
description: 'Main API client class',
|
|
80
|
-
members: [
|
|
81
|
-
{
|
|
82
|
-
name: 'baseUrl',
|
|
83
|
-
kind: 'property',
|
|
84
|
-
schema: { type: 'string' },
|
|
85
|
-
description: 'The base URL',
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
name: 'fetch',
|
|
89
|
-
kind: 'method',
|
|
90
|
-
signatures: [
|
|
91
|
-
{
|
|
92
|
-
parameters: [{ name: 'path', schema: { type: 'string' } }],
|
|
93
|
-
returns: { schema: { type: 'Promise<Response>' } },
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
description: 'Fetch data from the API',
|
|
97
|
-
},
|
|
98
|
-
],
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
id: 'LogLevel',
|
|
102
|
-
name: 'LogLevel',
|
|
103
|
-
kind: 'enum',
|
|
104
|
-
description: 'Log level values',
|
|
105
|
-
members: [
|
|
106
|
-
{ name: 'DEBUG', kind: 'property', description: 'Debug level' },
|
|
107
|
-
{ name: 'INFO', kind: 'property', description: 'Info level' },
|
|
108
|
-
{ name: 'ERROR', kind: 'property', description: 'Error level' },
|
|
109
|
-
],
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
id: 'VERSION',
|
|
113
|
-
name: 'VERSION',
|
|
114
|
-
kind: 'variable',
|
|
115
|
-
description: 'Package version string',
|
|
116
|
-
schema: { type: 'string', const: '1.0.0' },
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
id: 'RequestHandler',
|
|
120
|
-
name: 'RequestHandler',
|
|
121
|
-
kind: 'type',
|
|
122
|
-
description: 'Request handler type',
|
|
123
|
-
type: '(req: Request) => Promise<Response>',
|
|
124
|
-
},
|
|
125
|
-
],
|
|
126
|
-
types: [
|
|
127
|
-
{
|
|
128
|
-
id: 'Client',
|
|
129
|
-
name: 'Client',
|
|
130
|
-
kind: 'interface',
|
|
131
|
-
members: [{ name: 'fetch', kind: 'method' }],
|
|
132
|
-
},
|
|
133
|
-
],
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
describe('docs command', () => {
|
|
137
|
-
let tmpDir: string;
|
|
138
|
-
|
|
139
|
-
beforeAll(() => {
|
|
140
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openpkg-docs-test-'));
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
afterAll(() => {
|
|
144
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
describe('createDocs / loadSpec', () => {
|
|
148
|
-
test('creates docs instance from spec object', () => {
|
|
149
|
-
const docs = loadSpec(testSpec);
|
|
150
|
-
|
|
151
|
-
expect(docs.spec).toBe(testSpec);
|
|
152
|
-
expect(docs.getAllExports().length).toBe(6);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
test('creates docs instance from file path', () => {
|
|
156
|
-
const specPath = path.join(tmpDir, 'test-spec.json');
|
|
157
|
-
fs.writeFileSync(specPath, JSON.stringify(testSpec));
|
|
158
|
-
|
|
159
|
-
const docs = createDocs(specPath);
|
|
160
|
-
|
|
161
|
-
expect(docs.spec.meta.name).toBe('test-package');
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
test('getExport returns correct export', () => {
|
|
165
|
-
const docs = loadSpec(testSpec);
|
|
166
|
-
|
|
167
|
-
const fn = docs.getExport('createClient');
|
|
168
|
-
expect(fn).toBeDefined();
|
|
169
|
-
expect(fn!.kind).toBe('function');
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
test('getExportsByKind filters correctly', () => {
|
|
173
|
-
const docs = loadSpec(testSpec);
|
|
174
|
-
|
|
175
|
-
const functions = docs.getExportsByKind('function');
|
|
176
|
-
expect(functions.length).toBe(1);
|
|
177
|
-
expect(functions[0].name).toBe('createClient');
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
describe('markdown generation', () => {
|
|
182
|
-
test('generates markdown with frontmatter', () => {
|
|
183
|
-
const markdown = toMarkdown(testSpec, { frontmatter: true });
|
|
184
|
-
|
|
185
|
-
expect(markdown).toContain('---');
|
|
186
|
-
expect(markdown).toContain('title:');
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
test('generates markdown without frontmatter', () => {
|
|
190
|
-
const markdown = toMarkdown(testSpec, { frontmatter: false });
|
|
191
|
-
|
|
192
|
-
expect(markdown.startsWith('---')).toBe(false);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
test('contains API reference heading', () => {
|
|
196
|
-
const markdown = toMarkdown(testSpec);
|
|
197
|
-
|
|
198
|
-
expect(markdown).toContain('# test-package API Reference');
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
test('includes all exports', () => {
|
|
202
|
-
const markdown = toMarkdown(testSpec);
|
|
203
|
-
|
|
204
|
-
expect(markdown).toContain('createClient');
|
|
205
|
-
expect(markdown).toContain('Config');
|
|
206
|
-
expect(markdown).toContain('ApiClient');
|
|
207
|
-
expect(markdown).toContain('LogLevel');
|
|
208
|
-
expect(markdown).toContain('VERSION');
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
test('groups exports by kind', () => {
|
|
212
|
-
const markdown = toMarkdown(testSpec);
|
|
213
|
-
|
|
214
|
-
expect(markdown).toContain('## Functions');
|
|
215
|
-
// Note: doc generator uses simple pluralization (kind + 's'), so 'class' -> 'Classs'
|
|
216
|
-
expect(markdown).toContain('## Class');
|
|
217
|
-
expect(markdown).toContain('## Interfaces');
|
|
218
|
-
expect(markdown).toContain('## Enums');
|
|
219
|
-
expect(markdown).toContain('## Variables');
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
test('includes function parameters', () => {
|
|
223
|
-
const markdown = toMarkdown(testSpec);
|
|
224
|
-
|
|
225
|
-
expect(markdown).toContain('config');
|
|
226
|
-
expect(markdown).toContain('Parameters');
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
test('includes examples', () => {
|
|
230
|
-
const markdown = toMarkdown(testSpec);
|
|
231
|
-
|
|
232
|
-
expect(markdown).toContain('Examples');
|
|
233
|
-
expect(markdown).toContain('createClient({');
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
test('renders single export', () => {
|
|
237
|
-
const markdown = toMarkdown(testSpec, { export: 'createClient' });
|
|
238
|
-
|
|
239
|
-
expect(markdown).toContain('# createClient');
|
|
240
|
-
expect(markdown).not.toContain('# Config');
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
test('exportToMarkdown renders single export', () => {
|
|
244
|
-
const exp = testSpec.exports.find((e) => e.name === 'createClient')!;
|
|
245
|
-
const markdown = exportToMarkdown(exp, { frontmatter: true, codeSignatures: true });
|
|
246
|
-
|
|
247
|
-
expect(markdown).toContain('# createClient');
|
|
248
|
-
expect(markdown).toContain('```ts');
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
test('code signatures in fenced blocks', () => {
|
|
252
|
-
const markdown = toMarkdown(testSpec, { codeSignatures: true });
|
|
253
|
-
|
|
254
|
-
expect(markdown).toContain('```ts');
|
|
255
|
-
expect(markdown).toContain('```');
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
describe('HTML generation', () => {
|
|
260
|
-
test('generates full HTML document', () => {
|
|
261
|
-
const html = toHTML(testSpec, { fullDocument: true });
|
|
262
|
-
|
|
263
|
-
expect(html).toContain('<!DOCTYPE html>');
|
|
264
|
-
expect(html).toContain('<html');
|
|
265
|
-
expect(html).toContain('</html>');
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
test('generates HTML fragment', () => {
|
|
269
|
-
const html = toHTML(testSpec, { fullDocument: false });
|
|
270
|
-
|
|
271
|
-
expect(html).not.toContain('<!DOCTYPE html>');
|
|
272
|
-
expect(html).toContain('<header>');
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
test('includes inline styles by default', () => {
|
|
276
|
-
const html = toHTML(testSpec, { includeStyles: true });
|
|
277
|
-
|
|
278
|
-
expect(html).toContain('<style>');
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
test('excludes styles when disabled', () => {
|
|
282
|
-
const html = toHTML(testSpec, { includeStyles: false });
|
|
283
|
-
|
|
284
|
-
expect(html).not.toContain('<style>');
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
test('contains export names', () => {
|
|
288
|
-
const html = toHTML(testSpec);
|
|
289
|
-
|
|
290
|
-
expect(html).toContain('createClient');
|
|
291
|
-
expect(html).toContain('Config');
|
|
292
|
-
expect(html).toContain('ApiClient');
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
test('renders single export', () => {
|
|
296
|
-
const html = toHTML(testSpec, { export: 'createClient', fullDocument: false });
|
|
297
|
-
|
|
298
|
-
expect(html).toContain('createClient');
|
|
299
|
-
expect(html).not.toContain('ApiClient');
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
test('includes navigation', () => {
|
|
303
|
-
const html = toHTML(testSpec);
|
|
304
|
-
|
|
305
|
-
expect(html).toContain('<nav>');
|
|
306
|
-
expect(html).toContain('href="#');
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
test('escapes HTML in content', () => {
|
|
310
|
-
const specWithBrackets: OpenPkg = {
|
|
311
|
-
...testSpec,
|
|
312
|
-
exports: [
|
|
313
|
-
{
|
|
314
|
-
id: 'test',
|
|
315
|
-
name: 'test',
|
|
316
|
-
kind: 'function',
|
|
317
|
-
description: 'Returns <T> value',
|
|
318
|
-
signatures: [{ parameters: [] }],
|
|
319
|
-
},
|
|
320
|
-
],
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
const html = toHTML(specWithBrackets);
|
|
324
|
-
|
|
325
|
-
expect(html).toContain('<T>');
|
|
326
|
-
expect(html).not.toContain('<T>');
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
test('custom title override', () => {
|
|
330
|
-
const html = toHTML(testSpec, { title: 'Custom API Docs' });
|
|
331
|
-
|
|
332
|
-
expect(html).toContain('<title>Custom API Docs</title>');
|
|
333
|
-
});
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
describe('JSON format', () => {
|
|
337
|
-
test('returns simplified spec structure', () => {
|
|
338
|
-
const json = toJSON(testSpec) as SimplifiedSpec;
|
|
339
|
-
|
|
340
|
-
expect(json.name).toBe('test-package');
|
|
341
|
-
expect(json.version).toBe('1.0.0');
|
|
342
|
-
expect(json.description).toBe('A test package for docs generation');
|
|
343
|
-
expect(json.exports).toBeInstanceOf(Array);
|
|
344
|
-
expect(json.totalExports).toBe(6);
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
test('groups by kind', () => {
|
|
348
|
-
const json = toJSON(testSpec) as SimplifiedSpec;
|
|
349
|
-
|
|
350
|
-
expect(json.byKind).toBeDefined();
|
|
351
|
-
expect(json.byKind.function).toHaveLength(1);
|
|
352
|
-
expect(json.byKind.class).toHaveLength(1);
|
|
353
|
-
expect(json.byKind.interface).toHaveLength(1);
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
test('simplified export has required fields', () => {
|
|
357
|
-
const json = toJSON(testSpec) as SimplifiedSpec;
|
|
358
|
-
const fn = json.exports.find((e) => e.name === 'createClient');
|
|
359
|
-
|
|
360
|
-
expect(fn).toBeDefined();
|
|
361
|
-
expect(fn!.id).toBe('createClient');
|
|
362
|
-
expect(fn!.name).toBe('createClient');
|
|
363
|
-
expect(fn!.kind).toBe('function');
|
|
364
|
-
expect(fn!.signature).toBeDefined();
|
|
365
|
-
expect(fn!.deprecated).toBe(false);
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
test('function export has parameters and returns', () => {
|
|
369
|
-
const json = toJSON(testSpec) as SimplifiedSpec;
|
|
370
|
-
const fn = json.exports.find((e) => e.name === 'createClient');
|
|
371
|
-
|
|
372
|
-
expect(fn!.parameters).toBeDefined();
|
|
373
|
-
expect(fn!.parameters!.length).toBe(1);
|
|
374
|
-
expect(fn!.parameters![0].name).toBe('config');
|
|
375
|
-
expect(fn!.returns).toBeDefined();
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
test('class export has members', () => {
|
|
379
|
-
const json = toJSON(testSpec) as SimplifiedSpec;
|
|
380
|
-
const cls = json.exports.find((e) => e.name === 'ApiClient');
|
|
381
|
-
|
|
382
|
-
expect(cls!.members).toBeDefined();
|
|
383
|
-
expect(cls!.members!.length).toBe(2);
|
|
384
|
-
|
|
385
|
-
const prop = cls!.members!.find((m) => m.name === 'baseUrl');
|
|
386
|
-
expect(prop!.kind).toBe('property');
|
|
387
|
-
|
|
388
|
-
const method = cls!.members!.find((m) => m.name === 'fetch');
|
|
389
|
-
expect(method!.kind).toBe('method');
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
test('single export mode', () => {
|
|
393
|
-
const json = toJSON(testSpec, { export: 'createClient' }) as SimplifiedExport;
|
|
394
|
-
|
|
395
|
-
expect(json.id).toBe('createClient');
|
|
396
|
-
expect(json.name).toBe('createClient');
|
|
397
|
-
expect(json.kind).toBe('function');
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
test('toJSONString returns string', () => {
|
|
401
|
-
const jsonStr = toJSONString(testSpec);
|
|
402
|
-
|
|
403
|
-
expect(typeof jsonStr).toBe('string');
|
|
404
|
-
const parsed = JSON.parse(jsonStr);
|
|
405
|
-
expect(parsed.name).toBe('test-package');
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
test('toJSONString pretty option', () => {
|
|
409
|
-
const compact = toJSONString(testSpec, { pretty: false });
|
|
410
|
-
const pretty = toJSONString(testSpec, { pretty: true });
|
|
411
|
-
|
|
412
|
-
expect(compact).not.toContain('\n');
|
|
413
|
-
expect(pretty).toContain('\n');
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
test('examples simplified correctly', () => {
|
|
417
|
-
const json = toJSON(testSpec) as SimplifiedSpec;
|
|
418
|
-
const fn = json.exports.find((e) => e.name === 'createClient');
|
|
419
|
-
|
|
420
|
-
expect(fn!.examples).toBeDefined();
|
|
421
|
-
expect(fn!.examples!.length).toBe(1);
|
|
422
|
-
expect(fn!.examples![0].code).toContain('createClient');
|
|
423
|
-
expect(fn!.examples![0].title).toBe('Basic Usage');
|
|
424
|
-
});
|
|
425
|
-
});
|
|
426
|
-
|
|
427
|
-
describe('DocsInstance methods', () => {
|
|
428
|
-
test('toMarkdown method', () => {
|
|
429
|
-
const docs = loadSpec(testSpec);
|
|
430
|
-
const markdown = docs.toMarkdown();
|
|
431
|
-
|
|
432
|
-
expect(markdown).toContain('# test-package API Reference');
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
test('toHTML method', () => {
|
|
436
|
-
const docs = loadSpec(testSpec);
|
|
437
|
-
const html = docs.toHTML();
|
|
438
|
-
|
|
439
|
-
expect(html).toContain('<!DOCTYPE html>');
|
|
440
|
-
});
|
|
441
|
-
|
|
442
|
-
test('toJSON method', () => {
|
|
443
|
-
const docs = loadSpec(testSpec);
|
|
444
|
-
const json = docs.toJSON() as SimplifiedSpec;
|
|
445
|
-
|
|
446
|
-
expect(json.name).toBe('test-package');
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
test('search method', () => {
|
|
450
|
-
const docs = loadSpec(testSpec);
|
|
451
|
-
|
|
452
|
-
const results = docs.search('client');
|
|
453
|
-
expect(results.length).toBeGreaterThan(0);
|
|
454
|
-
expect(results.some((e) => e.name === 'createClient')).toBe(true);
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
test('groupByKind method', () => {
|
|
458
|
-
const docs = loadSpec(testSpec);
|
|
459
|
-
const groups = docs.groupByKind();
|
|
460
|
-
|
|
461
|
-
expect(groups.function).toBeDefined();
|
|
462
|
-
expect(groups.class).toBeDefined();
|
|
463
|
-
});
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
describe('split mode simulation', () => {
|
|
467
|
-
test('can write individual export markdown files', () => {
|
|
468
|
-
const outputDir = path.join(tmpDir, 'split-docs');
|
|
469
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
470
|
-
|
|
471
|
-
// Simulate split mode - write each export to separate file
|
|
472
|
-
for (const exp of testSpec.exports) {
|
|
473
|
-
const markdown = exportToMarkdown(exp, { frontmatter: true });
|
|
474
|
-
const filename = `${exp.name}.md`;
|
|
475
|
-
fs.writeFileSync(path.join(outputDir, filename), markdown);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// Verify files created
|
|
479
|
-
expect(fs.existsSync(path.join(outputDir, 'createClient.md'))).toBe(true);
|
|
480
|
-
expect(fs.existsSync(path.join(outputDir, 'Config.md'))).toBe(true);
|
|
481
|
-
expect(fs.existsSync(path.join(outputDir, 'ApiClient.md'))).toBe(true);
|
|
482
|
-
|
|
483
|
-
// Verify content
|
|
484
|
-
const clientMd = fs.readFileSync(path.join(outputDir, 'createClient.md'), 'utf-8');
|
|
485
|
-
expect(clientMd).toContain('# createClient');
|
|
486
|
-
});
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
describe('pipeline integration', () => {
|
|
490
|
-
test('spec JSON to docs markdown', () => {
|
|
491
|
-
// Simulate: openpkg spec | openpkg docs
|
|
492
|
-
const specJson = JSON.stringify(testSpec);
|
|
493
|
-
const spec: OpenPkg = JSON.parse(specJson);
|
|
494
|
-
const markdown = toMarkdown(spec);
|
|
495
|
-
|
|
496
|
-
expect(markdown).toContain('# test-package API Reference');
|
|
497
|
-
expect(markdown).toContain('createClient');
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
test('spec JSON to docs HTML', () => {
|
|
501
|
-
const specJson = JSON.stringify(testSpec);
|
|
502
|
-
const spec: OpenPkg = JSON.parse(specJson);
|
|
503
|
-
const html = toHTML(spec);
|
|
504
|
-
|
|
505
|
-
expect(html).toContain('<!DOCTYPE html>');
|
|
506
|
-
expect(html).toContain('createClient');
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
test('spec JSON to docs JSON', () => {
|
|
510
|
-
const specJson = JSON.stringify(testSpec);
|
|
511
|
-
const spec: OpenPkg = JSON.parse(specJson);
|
|
512
|
-
const json = toJSON(spec) as SimplifiedSpec;
|
|
513
|
-
|
|
514
|
-
expect(json.name).toBe('test-package');
|
|
515
|
-
expect(json.exports.length).toBe(6);
|
|
516
|
-
});
|
|
517
|
-
});
|
|
518
|
-
|
|
519
|
-
describe('error handling', () => {
|
|
520
|
-
test('throws for non-existent export in single mode', () => {
|
|
521
|
-
expect(() => {
|
|
522
|
-
toMarkdown(testSpec, { export: 'NonExistent' });
|
|
523
|
-
}).toThrow('Export not found: NonExistent');
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
test('throws for non-existent export in HTML', () => {
|
|
527
|
-
expect(() => {
|
|
528
|
-
toHTML(testSpec, { export: 'NonExistent' });
|
|
529
|
-
}).toThrow('Export not found: NonExistent');
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
test('throws for non-existent export in JSON', () => {
|
|
533
|
-
expect(() => {
|
|
534
|
-
toJSON(testSpec, { export: 'NonExistent' });
|
|
535
|
-
}).toThrow('Export not found: NonExistent');
|
|
536
|
-
});
|
|
537
|
-
|
|
538
|
-
test('throws for non-existent file', () => {
|
|
539
|
-
expect(() => {
|
|
540
|
-
createDocs('/non/existent/path.json');
|
|
541
|
-
}).toThrow();
|
|
542
|
-
});
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
describe('edge cases', () => {
|
|
546
|
-
test('handles empty exports array', () => {
|
|
547
|
-
const emptySpec: OpenPkg = {
|
|
548
|
-
openpkg: '0.4.0',
|
|
549
|
-
meta: { name: 'empty' },
|
|
550
|
-
exports: [],
|
|
551
|
-
types: [],
|
|
552
|
-
};
|
|
553
|
-
|
|
554
|
-
const markdown = toMarkdown(emptySpec);
|
|
555
|
-
expect(markdown).toContain('# empty API Reference');
|
|
556
|
-
|
|
557
|
-
const json = toJSON(emptySpec) as SimplifiedSpec;
|
|
558
|
-
expect(json.totalExports).toBe(0);
|
|
559
|
-
});
|
|
560
|
-
|
|
561
|
-
test('handles export without description', () => {
|
|
562
|
-
const spec: OpenPkg = {
|
|
563
|
-
openpkg: '0.4.0',
|
|
564
|
-
meta: { name: 'test' },
|
|
565
|
-
exports: [{ id: 'fn', name: 'fn', kind: 'function', signatures: [] }],
|
|
566
|
-
types: [],
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
const markdown = toMarkdown(spec);
|
|
570
|
-
expect(markdown).toContain('fn');
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
test('handles deprecated exports', () => {
|
|
574
|
-
const spec: OpenPkg = {
|
|
575
|
-
openpkg: '0.4.0',
|
|
576
|
-
meta: { name: 'test' },
|
|
577
|
-
exports: [
|
|
578
|
-
{
|
|
579
|
-
id: 'oldFn',
|
|
580
|
-
name: 'oldFn',
|
|
581
|
-
kind: 'function',
|
|
582
|
-
deprecated: true,
|
|
583
|
-
signatures: [],
|
|
584
|
-
},
|
|
585
|
-
],
|
|
586
|
-
types: [],
|
|
587
|
-
};
|
|
588
|
-
|
|
589
|
-
const markdown = toMarkdown(spec);
|
|
590
|
-
expect(markdown).toContain('Deprecated');
|
|
591
|
-
|
|
592
|
-
const html = toHTML(spec);
|
|
593
|
-
expect(html).toContain('Deprecated');
|
|
594
|
-
|
|
595
|
-
const json = toJSON(spec) as SimplifiedSpec;
|
|
596
|
-
expect(json.exports[0].deprecated).toBe(true);
|
|
597
|
-
});
|
|
598
|
-
});
|
|
599
|
-
});
|