@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/get.test.ts
DELETED
|
@@ -1,413 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test';
|
|
2
|
-
import { getExport } from '@openpkg-ts/sdk';
|
|
3
|
-
|
|
4
|
-
describe('getExport', () => {
|
|
5
|
-
describe('function exports', () => {
|
|
6
|
-
test('gets function with signature and parameters', async () => {
|
|
7
|
-
const code = `
|
|
8
|
-
/** Creates a new client */
|
|
9
|
-
export function createClient(config: Config): Client {
|
|
10
|
-
return {} as Client;
|
|
11
|
-
}
|
|
12
|
-
interface Config { baseUrl: string; }
|
|
13
|
-
interface Client { fetch(): void; }
|
|
14
|
-
`;
|
|
15
|
-
|
|
16
|
-
const result = await getExport({
|
|
17
|
-
entryFile: 'test.ts',
|
|
18
|
-
exportName: 'createClient',
|
|
19
|
-
content: code,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
expect(result.errors).toHaveLength(0);
|
|
23
|
-
expect(result.export).not.toBeNull();
|
|
24
|
-
expect(result.export!.kind).toBe('function');
|
|
25
|
-
expect(result.export!.signatures).toBeDefined();
|
|
26
|
-
expect(result.export!.signatures).toHaveLength(1);
|
|
27
|
-
|
|
28
|
-
const sig = result.export!.signatures![0];
|
|
29
|
-
expect(sig.parameters).toHaveLength(1);
|
|
30
|
-
expect(sig.parameters![0].name).toBe('config');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('gets arrow function export', async () => {
|
|
34
|
-
const code = `
|
|
35
|
-
/** Arrow function export */
|
|
36
|
-
export const add = (a: number, b: number): number => a + b;
|
|
37
|
-
`;
|
|
38
|
-
|
|
39
|
-
const result = await getExport({ entryFile: 'test.ts', exportName: 'add', content: code });
|
|
40
|
-
|
|
41
|
-
expect(result.errors).toHaveLength(0);
|
|
42
|
-
expect(result.export).not.toBeNull();
|
|
43
|
-
// Arrow functions assigned to const are classified as variables at declaration level
|
|
44
|
-
// but listExports detects them as functions via type analysis
|
|
45
|
-
expect(['function', 'variable']).toContain(result.export!.kind);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('gets function with overloads', async () => {
|
|
49
|
-
const code = `
|
|
50
|
-
/** @overload */
|
|
51
|
-
export function parse(input: string): object;
|
|
52
|
-
/** @overload */
|
|
53
|
-
export function parse(input: Buffer): object;
|
|
54
|
-
export function parse(input: string | Buffer): object {
|
|
55
|
-
return {};
|
|
56
|
-
}
|
|
57
|
-
`;
|
|
58
|
-
|
|
59
|
-
const result = await getExport({ entryFile: 'test.ts', exportName: 'parse', content: code });
|
|
60
|
-
|
|
61
|
-
expect(result.errors).toHaveLength(0);
|
|
62
|
-
expect(result.export!.kind).toBe('function');
|
|
63
|
-
// Should have multiple signatures for overloads
|
|
64
|
-
expect(result.export!.signatures!.length).toBeGreaterThanOrEqual(1);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
describe('interface exports', () => {
|
|
69
|
-
test('gets interface with properties', async () => {
|
|
70
|
-
const code = `
|
|
71
|
-
/** Configuration interface */
|
|
72
|
-
export interface Config {
|
|
73
|
-
/** Base URL for API */
|
|
74
|
-
baseUrl: string;
|
|
75
|
-
/** Optional timeout */
|
|
76
|
-
timeout?: number;
|
|
77
|
-
}
|
|
78
|
-
`;
|
|
79
|
-
|
|
80
|
-
const result = await getExport({ entryFile: 'test.ts', exportName: 'Config', content: code });
|
|
81
|
-
|
|
82
|
-
expect(result.errors).toHaveLength(0);
|
|
83
|
-
expect(result.export).not.toBeNull();
|
|
84
|
-
expect(result.export!.kind).toBe('interface');
|
|
85
|
-
expect(result.export!.members).toBeDefined();
|
|
86
|
-
expect(result.export!.members!.length).toBe(2);
|
|
87
|
-
|
|
88
|
-
const baseUrl = result.export!.members!.find((m: { name: string }) => m.name === 'baseUrl');
|
|
89
|
-
expect(baseUrl).toBeDefined();
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test('gets interface with methods', async () => {
|
|
93
|
-
const code = `
|
|
94
|
-
/** Client interface */
|
|
95
|
-
export interface Client {
|
|
96
|
-
/** Fetch data */
|
|
97
|
-
fetch(url: string): Promise<Response>;
|
|
98
|
-
}
|
|
99
|
-
`;
|
|
100
|
-
|
|
101
|
-
const result = await getExport({ entryFile: 'test.ts', exportName: 'Client', content: code });
|
|
102
|
-
|
|
103
|
-
expect(result.errors).toHaveLength(0);
|
|
104
|
-
expect(result.export!.kind).toBe('interface');
|
|
105
|
-
expect(result.export!.members).toBeDefined();
|
|
106
|
-
|
|
107
|
-
const fetch = result.export!.members!.find((m: { name: string }) => m.name === 'fetch');
|
|
108
|
-
expect(fetch).toBeDefined();
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
describe('type alias exports', () => {
|
|
113
|
-
test('gets type alias', async () => {
|
|
114
|
-
const code = `
|
|
115
|
-
/** Union type */
|
|
116
|
-
export type Result = Success | Error;
|
|
117
|
-
interface Success { ok: true; data: unknown; }
|
|
118
|
-
interface Error { ok: false; error: string; }
|
|
119
|
-
`;
|
|
120
|
-
|
|
121
|
-
const result = await getExport({ entryFile: 'test.ts', exportName: 'Result', content: code });
|
|
122
|
-
|
|
123
|
-
expect(result.errors).toHaveLength(0);
|
|
124
|
-
expect(result.export).not.toBeNull();
|
|
125
|
-
expect(result.export!.kind).toBe('type');
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test('gets mapped type', async () => {
|
|
129
|
-
const code = `
|
|
130
|
-
/** Make all properties optional */
|
|
131
|
-
export type Partial<T> = { [K in keyof T]?: T[K] };
|
|
132
|
-
`;
|
|
133
|
-
|
|
134
|
-
const result = await getExport({
|
|
135
|
-
entryFile: 'test.ts',
|
|
136
|
-
exportName: 'Partial',
|
|
137
|
-
content: code,
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
expect(result.errors).toHaveLength(0);
|
|
141
|
-
expect(result.export!.kind).toBe('type');
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
describe('class exports', () => {
|
|
146
|
-
test('gets class with members', async () => {
|
|
147
|
-
const code = `
|
|
148
|
-
/** API Client class */
|
|
149
|
-
export class ApiClient {
|
|
150
|
-
/** Base URL */
|
|
151
|
-
baseUrl: string;
|
|
152
|
-
|
|
153
|
-
constructor(config: { baseUrl: string }) {
|
|
154
|
-
this.baseUrl = config.baseUrl;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/** Make request */
|
|
158
|
-
async request(path: string): Promise<Response> {
|
|
159
|
-
return fetch(this.baseUrl + path);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
`;
|
|
163
|
-
|
|
164
|
-
const result = await getExport({
|
|
165
|
-
entryFile: 'test.ts',
|
|
166
|
-
exportName: 'ApiClient',
|
|
167
|
-
content: code,
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
expect(result.errors).toHaveLength(0);
|
|
171
|
-
expect(result.export).not.toBeNull();
|
|
172
|
-
expect(result.export!.kind).toBe('class');
|
|
173
|
-
expect(result.export!.members).toBeDefined();
|
|
174
|
-
|
|
175
|
-
// Should have baseUrl property and request method
|
|
176
|
-
const members = result.export!.members!;
|
|
177
|
-
expect(members.some((m: { name: string }) => m.name === 'baseUrl')).toBe(true);
|
|
178
|
-
expect(members.some((m: { name: string }) => m.name === 'request')).toBe(true);
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
test('gets class with static members', async () => {
|
|
182
|
-
const code = `
|
|
183
|
-
/** Class with statics */
|
|
184
|
-
export class Utils {
|
|
185
|
-
static readonly VERSION = '1.0.0';
|
|
186
|
-
static format(s: string): string { return s; }
|
|
187
|
-
}
|
|
188
|
-
`;
|
|
189
|
-
|
|
190
|
-
const result = await getExport({ entryFile: 'test.ts', exportName: 'Utils', content: code });
|
|
191
|
-
|
|
192
|
-
expect(result.errors).toHaveLength(0);
|
|
193
|
-
expect(result.export!.kind).toBe('class');
|
|
194
|
-
|
|
195
|
-
const members = result.export!.members!;
|
|
196
|
-
const version = members.find((m: { name: string }) => m.name === 'VERSION');
|
|
197
|
-
const format = members.find((m: { name: string }) => m.name === 'format');
|
|
198
|
-
expect(version).toBeDefined();
|
|
199
|
-
expect(format).toBeDefined();
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
describe('enum exports', () => {
|
|
204
|
-
test('gets enum with members', async () => {
|
|
205
|
-
const code = `
|
|
206
|
-
/** Log levels */
|
|
207
|
-
export enum LogLevel {
|
|
208
|
-
DEBUG = 0,
|
|
209
|
-
INFO = 1,
|
|
210
|
-
WARN = 2,
|
|
211
|
-
ERROR = 3
|
|
212
|
-
}
|
|
213
|
-
`;
|
|
214
|
-
|
|
215
|
-
const result = await getExport({
|
|
216
|
-
entryFile: 'test.ts',
|
|
217
|
-
exportName: 'LogLevel',
|
|
218
|
-
content: code,
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
expect(result.errors).toHaveLength(0);
|
|
222
|
-
expect(result.export).not.toBeNull();
|
|
223
|
-
expect(result.export!.kind).toBe('enum');
|
|
224
|
-
expect(result.export!.members).toBeDefined();
|
|
225
|
-
expect(result.export!.members!.length).toBe(4);
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
test('gets string enum', async () => {
|
|
229
|
-
const code = `
|
|
230
|
-
/** Status values */
|
|
231
|
-
export enum Status {
|
|
232
|
-
Pending = 'pending',
|
|
233
|
-
Active = 'active',
|
|
234
|
-
Done = 'done'
|
|
235
|
-
}
|
|
236
|
-
`;
|
|
237
|
-
|
|
238
|
-
const result = await getExport({ entryFile: 'test.ts', exportName: 'Status', content: code });
|
|
239
|
-
|
|
240
|
-
expect(result.errors).toHaveLength(0);
|
|
241
|
-
expect(result.export!.kind).toBe('enum');
|
|
242
|
-
expect(result.export!.members!.length).toBe(3);
|
|
243
|
-
});
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
describe('variable exports', () => {
|
|
247
|
-
test('gets const variable', async () => {
|
|
248
|
-
const code = `
|
|
249
|
-
/** Default config */
|
|
250
|
-
export const DEFAULT_CONFIG = { timeout: 5000, retries: 3 };
|
|
251
|
-
`;
|
|
252
|
-
|
|
253
|
-
const result = await getExport({
|
|
254
|
-
entryFile: 'test.ts',
|
|
255
|
-
exportName: 'DEFAULT_CONFIG',
|
|
256
|
-
content: code,
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
expect(result.errors).toHaveLength(0);
|
|
260
|
-
expect(result.export).not.toBeNull();
|
|
261
|
-
expect(result.export!.kind).toBe('variable');
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
test('gets typed const', async () => {
|
|
265
|
-
const code = `
|
|
266
|
-
/** API version */
|
|
267
|
-
export const VERSION: string = '1.0.0';
|
|
268
|
-
`;
|
|
269
|
-
|
|
270
|
-
const result = await getExport({
|
|
271
|
-
entryFile: 'test.ts',
|
|
272
|
-
exportName: 'VERSION',
|
|
273
|
-
content: code,
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
expect(result.errors).toHaveLength(0);
|
|
277
|
-
expect(result.export!.kind).toBe('variable');
|
|
278
|
-
});
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
describe('namespace exports', () => {
|
|
282
|
-
test('gets namespace with exports', async () => {
|
|
283
|
-
const code = `
|
|
284
|
-
/** Utility namespace */
|
|
285
|
-
export namespace Utils {
|
|
286
|
-
export const PI = 3.14159;
|
|
287
|
-
export function square(n: number): number { return n * n; }
|
|
288
|
-
}
|
|
289
|
-
`;
|
|
290
|
-
|
|
291
|
-
const result = await getExport({ entryFile: 'test.ts', exportName: 'Utils', content: code });
|
|
292
|
-
|
|
293
|
-
// Namespace serialization may not be fully implemented
|
|
294
|
-
// Check that we at least get a result or a meaningful error
|
|
295
|
-
if (result.export) {
|
|
296
|
-
expect(result.export.kind).toBe('namespace');
|
|
297
|
-
} else {
|
|
298
|
-
// If namespace not supported, we expect a serialization error
|
|
299
|
-
expect(result.errors.length).toBeGreaterThan(0);
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
describe('error handling', () => {
|
|
305
|
-
test('returns error for non-existent export', async () => {
|
|
306
|
-
const code = `
|
|
307
|
-
export function myFunc(): void {}
|
|
308
|
-
`;
|
|
309
|
-
|
|
310
|
-
const result = await getExport({
|
|
311
|
-
entryFile: 'test.ts',
|
|
312
|
-
exportName: 'NonExistent',
|
|
313
|
-
content: code,
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
expect(result.export).toBeNull();
|
|
317
|
-
expect(result.errors.length).toBeGreaterThan(0);
|
|
318
|
-
expect(result.errors[0]).toContain("Export 'NonExistent' not found");
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
test('returns error for empty file', async () => {
|
|
322
|
-
const code = `// empty file`;
|
|
323
|
-
|
|
324
|
-
const result = await getExport({
|
|
325
|
-
entryFile: 'test.ts',
|
|
326
|
-
exportName: 'anything',
|
|
327
|
-
content: code,
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
expect(result.export).toBeNull();
|
|
331
|
-
expect(result.errors.length).toBeGreaterThan(0);
|
|
332
|
-
});
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
describe('related types', () => {
|
|
336
|
-
test('includes referenced types', async () => {
|
|
337
|
-
const code = `
|
|
338
|
-
export interface Response {
|
|
339
|
-
data: Data;
|
|
340
|
-
}
|
|
341
|
-
export interface Data {
|
|
342
|
-
id: string;
|
|
343
|
-
}
|
|
344
|
-
`;
|
|
345
|
-
|
|
346
|
-
const result = await getExport({
|
|
347
|
-
entryFile: 'test.ts',
|
|
348
|
-
exportName: 'Response',
|
|
349
|
-
content: code,
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
expect(result.errors).toHaveLength(0);
|
|
353
|
-
expect(result.export).not.toBeNull();
|
|
354
|
-
// Related types may be in result.types
|
|
355
|
-
// Depends on implementation - Data may or may not be included
|
|
356
|
-
});
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
describe('output structure', () => {
|
|
360
|
-
test('output matches spec format', async () => {
|
|
361
|
-
const code = `
|
|
362
|
-
/** Creates something */
|
|
363
|
-
export function create(name: string): void {}
|
|
364
|
-
`;
|
|
365
|
-
|
|
366
|
-
const result = await getExport({ entryFile: 'test.ts', exportName: 'create', content: code });
|
|
367
|
-
|
|
368
|
-
expect(result.export).not.toBeNull();
|
|
369
|
-
|
|
370
|
-
// Verify spec structure
|
|
371
|
-
const exp = result.export!;
|
|
372
|
-
expect(exp.kind).toBe('function');
|
|
373
|
-
expect(exp.name).toBe('create');
|
|
374
|
-
expect(typeof exp.description).toBe('string');
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
test('result has export, types, errors fields', async () => {
|
|
378
|
-
const code = `export const x = 1;`;
|
|
379
|
-
|
|
380
|
-
const result = await getExport({ entryFile: 'test.ts', exportName: 'x', content: code });
|
|
381
|
-
|
|
382
|
-
expect(result).toHaveProperty('export');
|
|
383
|
-
expect(result).toHaveProperty('types');
|
|
384
|
-
expect(result).toHaveProperty('errors');
|
|
385
|
-
expect(Array.isArray(result.types)).toBe(true);
|
|
386
|
-
expect(Array.isArray(result.errors)).toBe(true);
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
describe('performance', () => {
|
|
391
|
-
test('single export lookup is reasonably fast', async () => {
|
|
392
|
-
const code = `
|
|
393
|
-
export function myFunc(): void {}
|
|
394
|
-
export interface MyInterface { value: string; }
|
|
395
|
-
export class MyClass { prop: number = 0; }
|
|
396
|
-
export type MyType = string | number;
|
|
397
|
-
export const myVar = 42;
|
|
398
|
-
export enum MyEnum { A, B, C }
|
|
399
|
-
`;
|
|
400
|
-
|
|
401
|
-
// Each call creates a new TypeScript program, so overhead is expected
|
|
402
|
-
// Target: under 2s for cold start, which is acceptable for CLI usage
|
|
403
|
-
const start = performance.now();
|
|
404
|
-
const result = await getExport({ entryFile: 'test.ts', exportName: 'myFunc', content: code });
|
|
405
|
-
const elapsed = performance.now() - start;
|
|
406
|
-
|
|
407
|
-
expect(result.errors).toHaveLength(0);
|
|
408
|
-
expect(result.export).not.toBeNull();
|
|
409
|
-
// 2s is generous but accounts for CI variance
|
|
410
|
-
expect(elapsed).toBeLessThan(2000);
|
|
411
|
-
});
|
|
412
|
-
});
|
|
413
|
-
});
|