jsdoczoom 0.4.11 → 0.4.13

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 (61) hide show
  1. package/dist/{src/drilldown.js → drilldown.js} +9 -6
  2. package/package.json +2 -2
  3. package/dist/test/barrel.test.js +0 -77
  4. package/dist/test/cache.test.js +0 -222
  5. package/dist/test/cli.test.js +0 -479
  6. package/dist/test/drilldown-barrel.test.js +0 -383
  7. package/dist/test/drilldown.test.js +0 -469
  8. package/dist/test/errors.test.js +0 -26
  9. package/dist/test/eslint-engine.test.js +0 -130
  10. package/dist/test/eslint-plugin.test.js +0 -291
  11. package/dist/test/file-discovery.test.js +0 -72
  12. package/dist/test/jsdoc-parser.test.js +0 -353
  13. package/dist/test/lint.test.js +0 -413
  14. package/dist/test/selector.test.js +0 -93
  15. package/dist/test/type-declarations.test.js +0 -321
  16. package/dist/test/validate.test.js +0 -361
  17. package/types/test/barrel.test.d.ts +0 -1
  18. package/types/test/cache.test.d.ts +0 -8
  19. package/types/test/cli.test.d.ts +0 -1
  20. package/types/test/drilldown-barrel.test.d.ts +0 -1
  21. package/types/test/drilldown.test.d.ts +0 -1
  22. package/types/test/errors.test.d.ts +0 -1
  23. package/types/test/eslint-engine.test.d.ts +0 -6
  24. package/types/test/eslint-plugin.test.d.ts +0 -1
  25. package/types/test/file-discovery.test.d.ts +0 -1
  26. package/types/test/jsdoc-parser.test.d.ts +0 -1
  27. package/types/test/lint.test.d.ts +0 -9
  28. package/types/test/selector.test.d.ts +0 -1
  29. package/types/test/type-declarations.test.d.ts +0 -1
  30. package/types/test/validate.test.d.ts +0 -1
  31. /package/dist/{src/barrel.js → barrel.js} +0 -0
  32. /package/dist/{src/cache.js → cache.js} +0 -0
  33. /package/dist/{src/cli.js → cli.js} +0 -0
  34. /package/dist/{src/errors.js → errors.js} +0 -0
  35. /package/dist/{src/eslint-engine.js → eslint-engine.js} +0 -0
  36. /package/dist/{src/eslint-plugin.js → eslint-plugin.js} +0 -0
  37. /package/dist/{src/file-discovery.js → file-discovery.js} +0 -0
  38. /package/dist/{src/index.js → index.js} +0 -0
  39. /package/dist/{src/jsdoc-parser.js → jsdoc-parser.js} +0 -0
  40. /package/dist/{src/lint.js → lint.js} +0 -0
  41. /package/dist/{src/selector.js → selector.js} +0 -0
  42. /package/dist/{src/skill-text.js → skill-text.js} +0 -0
  43. /package/dist/{src/type-declarations.js → type-declarations.js} +0 -0
  44. /package/dist/{src/types.js → types.js} +0 -0
  45. /package/dist/{src/validate.js → validate.js} +0 -0
  46. /package/types/{src/barrel.d.ts → barrel.d.ts} +0 -0
  47. /package/types/{src/cache.d.ts → cache.d.ts} +0 -0
  48. /package/types/{src/cli.d.ts → cli.d.ts} +0 -0
  49. /package/types/{src/drilldown.d.ts → drilldown.d.ts} +0 -0
  50. /package/types/{src/errors.d.ts → errors.d.ts} +0 -0
  51. /package/types/{src/eslint-engine.d.ts → eslint-engine.d.ts} +0 -0
  52. /package/types/{src/eslint-plugin.d.ts → eslint-plugin.d.ts} +0 -0
  53. /package/types/{src/file-discovery.d.ts → file-discovery.d.ts} +0 -0
  54. /package/types/{src/index.d.ts → index.d.ts} +0 -0
  55. /package/types/{src/jsdoc-parser.d.ts → jsdoc-parser.d.ts} +0 -0
  56. /package/types/{src/lint.d.ts → lint.d.ts} +0 -0
  57. /package/types/{src/selector.d.ts → selector.d.ts} +0 -0
  58. /package/types/{src/skill-text.d.ts → skill-text.d.ts} +0 -0
  59. /package/types/{src/type-declarations.d.ts → type-declarations.d.ts} +0 -0
  60. /package/types/{src/types.d.ts → types.d.ts} +0 -0
  61. /package/types/{src/validate.d.ts → validate.d.ts} +0 -0
@@ -1,353 +0,0 @@
1
- import fs from "node:fs";
2
- import os from "node:os";
3
- import path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { describe, expect, it } from "vitest";
6
- import { JsdocError } from "../src/errors.js";
7
- import { extractFileJsdoc, parseFileSummaries } from "../src/jsdoc-parser.js";
8
-
9
- /**
10
- * Verifies extraction of file-level JSDoc blocks before code statements,
11
- * multi-line summary joining, whitespace-only summary skipping, tag isolation,
12
- * and PARSE_ERROR on syntax errors. Uses both fixture files and temp files.
13
- *
14
- * @summary Tests for JSDoc extraction and summary/description parsing
15
- */
16
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
- const fixturesDir = path.resolve(__dirname, "fixtures", "leaf-files");
18
- function fixture(name) {
19
- return path.join(fixturesDir, name);
20
- }
21
- /** Write source to a temp .ts file, run the callback, then clean up. */
22
- function withTempFile(source, fn) {
23
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "jsdoczoom-test-"));
24
- const tmpFile = path.join(tmpDir, "temp.ts");
25
- fs.writeFileSync(tmpFile, source);
26
- try {
27
- fn(tmpFile);
28
- } finally {
29
- fs.rmSync(tmpDir, { recursive: true });
30
- }
31
- }
32
- describe("extractFileJsdoc", () => {
33
- it("extracts first /** */ block before code statements", () => {
34
- const source = [
35
- "/**",
36
- " * Hello world.",
37
- " *",
38
- " * @summary A summary",
39
- " */",
40
- "",
41
- "export const x = 1;",
42
- ].join("\n");
43
- const result = extractFileJsdoc(source);
44
- expect(result).not.toBeNull();
45
- expect(result).toContain("Hello world.");
46
- expect(result).toContain("@summary A summary");
47
- });
48
- it("JSDoc after import statements is valid (extracted correctly)", () => {
49
- const source = [
50
- "import { readFileSync } from 'fs';",
51
- "",
52
- "/**",
53
- " * This JSDoc appears after imports but before code.",
54
- " *",
55
- " * @summary After imports summary",
56
- " */",
57
- "",
58
- "export function doSomething(): string {",
59
- " return readFileSync('/dev/null', 'utf-8');",
60
- "}",
61
- ].join("\n");
62
- const result = extractFileJsdoc(source);
63
- expect(result).not.toBeNull();
64
- expect(result).toContain(
65
- "This JSDoc appears after imports but before code.",
66
- );
67
- expect(result).toContain("@summary After imports summary");
68
- });
69
- it("ignores JSDoc blocks that appear after code statements", () => {
70
- const source = [
71
- "export const x = 1;",
72
- "",
73
- "/**",
74
- " * This JSDoc is after code, so it should not be the file-level JSDoc.",
75
- " *",
76
- " * @summary Should be ignored",
77
- " */",
78
- "",
79
- "export const y = 2;",
80
- ].join("\n");
81
- const result = extractFileJsdoc(source);
82
- expect(result).toBeNull();
83
- });
84
- it("handles TypeScript syntax errors (throws PARSE_ERROR)", () => {
85
- const source = "export const broken: = { this is not valid };";
86
- expect(() => extractFileJsdoc(source)).toThrow(JsdocError);
87
- try {
88
- extractFileJsdoc(source);
89
- } catch (e) {
90
- expect(e).toBeInstanceOf(JsdocError);
91
- expect(e.code).toBe("PARSE_ERROR");
92
- }
93
- });
94
- it("literal @ in prose (like user@example.com) does not start a new tag", () => {
95
- const source = [
96
- "/**",
97
- " * Contact user@example.com for more info.",
98
- " *",
99
- " * @summary Email module summary",
100
- " */",
101
- "",
102
- "export const x = 1;",
103
- ].join("\n");
104
- const result = extractFileJsdoc(source);
105
- expect(result).not.toBeNull();
106
- expect(result).toContain("user@example.com");
107
- });
108
- });
109
- describe("parseFileSummaries", () => {
110
- it("extracts first @summary tag", () => {
111
- const result = parseFileSummaries(fixture("two-summaries.ts"));
112
- expect(result.hasFileJsdoc).toBe(true);
113
- expect(result.summary).toBe("First summary - concise overview");
114
- expect(result.description).toBe(
115
- "This is the free-text description of the module.",
116
- );
117
- });
118
- it("joins multi-line @summary content with spaces", () => {
119
- const result = parseFileSummaries(fixture("multi-line-summary.ts"));
120
- expect(result.hasFileJsdoc).toBe(true);
121
- expect(result.summary).toBe(
122
- "This is a multi-line summary that spans across multiple lines and should be joined with spaces",
123
- );
124
- expect(result.description).toBe("Module description.");
125
- });
126
- it("skips whitespace-only @summary, uses next non-empty one", () => {
127
- const result = parseFileSummaries(fixture("whitespace-summary.ts"));
128
- expect(result.hasFileJsdoc).toBe(true);
129
- expect(result.summary).toBe("Real summary here");
130
- expect(result.description).toBe("Module with whitespace summaries.");
131
- });
132
- it("returns free-text as description field", () => {
133
- const result = parseFileSummaries(fixture("one-summary.ts"));
134
- expect(result.hasFileJsdoc).toBe(true);
135
- expect(result.summary).toBe("Single summary line");
136
- expect(result.description).toBe("Module description as free-text.");
137
- });
138
- it("summary is null, description is the free-text", () => {
139
- const result = parseFileSummaries(fixture("description-only.ts"));
140
- expect(result.hasFileJsdoc).toBe(true);
141
- expect(result.summary).toBeNull();
142
- expect(result.description).toBe(
143
- "This module only has a free-text description with no @summary tags.",
144
- );
145
- });
146
- it("summary null, description null, hasFileJsdoc false", () => {
147
- const result = parseFileSummaries(fixture("no-jsdoc.ts"));
148
- expect(result.hasFileJsdoc).toBe(false);
149
- expect(result.summary).toBeNull();
150
- expect(result.description).toBeNull();
151
- });
152
- it("only recognizes exact lowercase @summary", () => {
153
- const source = [
154
- "/**",
155
- " * Free text here.",
156
- " *",
157
- " * @Summary Uppercase summary",
158
- " * @SUMMARY All caps summary",
159
- " * @summary Real summary",
160
- " */",
161
- "",
162
- "export const x = 1;",
163
- ].join("\n");
164
- withTempFile(source, (tmpFile) => {
165
- const result = parseFileSummaries(tmpFile);
166
- expect(result.hasFileJsdoc).toBe(true);
167
- expect(result.summary).toBe("Real summary");
168
- expect(result.summaryCount).toBe(1);
169
- expect(result.description).toBe("Free text here.");
170
- });
171
- });
172
- it("@Summary without lowercase @summary results in missing summary", () => {
173
- const source = [
174
- "/**",
175
- " * Description.",
176
- " *",
177
- " * @Summary Uppercase summary",
178
- " */",
179
- "",
180
- "export const x = 1;",
181
- ].join("\n");
182
- withTempFile(source, (tmpFile) => {
183
- const result = parseFileSummaries(tmpFile);
184
- expect(result.hasFileJsdoc).toBe(true);
185
- expect(result.summary).toBeNull();
186
- expect(result.summaryCount).toBe(0);
187
- });
188
- });
189
- it("@desc tag content is included in description", () => {
190
- const source = [
191
- "/**",
192
- " * @desc Module description via desc tag.",
193
- " *",
194
- " * @summary My summary",
195
- " */",
196
- "",
197
- "export const x = 1;",
198
- ].join("\n");
199
- withTempFile(source, (tmpFile) => {
200
- const result = parseFileSummaries(tmpFile);
201
- expect(result.summary).toBe("My summary");
202
- expect(result.description).toBe("Module description via desc tag.");
203
- });
204
- });
205
- it("@description tag content is included in description", () => {
206
- const source = [
207
- "/**",
208
- " * @description Full description tag content.",
209
- " *",
210
- " * @summary My summary",
211
- " */",
212
- "",
213
- "export const x = 1;",
214
- ].join("\n");
215
- withTempFile(source, (tmpFile) => {
216
- const result = parseFileSummaries(tmpFile);
217
- expect(result.summary).toBe("My summary");
218
- expect(result.description).toBe("Full description tag content.");
219
- });
220
- });
221
- it("@file and @fileoverview tags are included in description", () => {
222
- const source = [
223
- "/**",
224
- " * @file File-level overview.",
225
- " *",
226
- " * @summary My summary",
227
- " */",
228
- "",
229
- "export const x = 1;",
230
- ].join("\n");
231
- withTempFile(source, (tmpFile) => {
232
- const result = parseFileSummaries(tmpFile);
233
- expect(result.summary).toBe("My summary");
234
- expect(result.description).toBe("File-level overview.");
235
- });
236
- });
237
- it("free-text and @description tag are combined in description", () => {
238
- const source = [
239
- "/**",
240
- " * Free text first.",
241
- " *",
242
- " * @description Additional description.",
243
- " *",
244
- " * @summary My summary",
245
- " */",
246
- "",
247
- "export const x = 1;",
248
- ].join("\n");
249
- withTempFile(source, (tmpFile) => {
250
- const result = parseFileSummaries(tmpFile);
251
- expect(result.summary).toBe("My summary");
252
- expect(result.description).toBe(
253
- "Free text first. Additional description.",
254
- );
255
- });
256
- });
257
- it("@description continuation lines are included in description", () => {
258
- const source = [
259
- "/**",
260
- " * @description First line of description",
261
- " * continues on this line.",
262
- " *",
263
- " * @summary My summary",
264
- " */",
265
- "",
266
- "export const x = 1;",
267
- ].join("\n");
268
- withTempFile(source, (tmpFile) => {
269
- const result = parseFileSummaries(tmpFile);
270
- expect(result.summary).toBe("My summary");
271
- expect(result.description).toBe(
272
- "First line of description continues on this line.",
273
- );
274
- });
275
- });
276
- it("summaryCount is 1 for single @summary", () => {
277
- const result = parseFileSummaries(fixture("one-summary.ts"));
278
- expect(result.summaryCount).toBe(1);
279
- });
280
- it("summaryCount is 0 for no @summary", () => {
281
- const result = parseFileSummaries(fixture("description-only.ts"));
282
- expect(result.summaryCount).toBe(0);
283
- });
284
- it("summaryCount tracks multiple @summary tags", () => {
285
- const result = parseFileSummaries(fixture("multiple-summaries.ts"));
286
- expect(result.summaryCount).toBe(2);
287
- expect(result.summary).toBe("First summary tag");
288
- });
289
- it("handles TypeScript syntax errors (throws PARSE_ERROR)", () => {
290
- expect(() => parseFileSummaries(fixture("syntax-error.ts"))).toThrow(
291
- JsdocError,
292
- );
293
- try {
294
- parseFileSummaries(fixture("syntax-error.ts"));
295
- } catch (e) {
296
- expect(e).toBeInstanceOf(JsdocError);
297
- expect(e.code).toBe("PARSE_ERROR");
298
- }
299
- });
300
- it("@param after @summary does not corrupt summary", () => {
301
- const source = [
302
- "/**",
303
- " * Module with various tags.",
304
- " *",
305
- " * @summary The real summary",
306
- " * @param x - some param",
307
- " * @returns nothing",
308
- " * @deprecated Use something else",
309
- " */",
310
- "",
311
- "export const x = 1;",
312
- ].join("\n");
313
- withTempFile(source, (tmpFile) => {
314
- const result = parseFileSummaries(tmpFile);
315
- expect(result.hasFileJsdoc).toBe(true);
316
- expect(result.summary).toBe("The real summary");
317
- expect(result.description).toBe("Module with various tags.");
318
- });
319
- });
320
- it("ignores second @summary tag, uses only first", () => {
321
- const source = [
322
- "/**",
323
- " * Module description.",
324
- " *",
325
- " * @summary First summary",
326
- " * @param x - some param",
327
- " * @summary Second summary",
328
- " */",
329
- "",
330
- "export const x = 1;",
331
- ].join("\n");
332
- withTempFile(source, (tmpFile) => {
333
- const result = parseFileSummaries(tmpFile);
334
- expect(result.hasFileJsdoc).toBe(true);
335
- expect(result.summary).toBe("First summary");
336
- expect(result.description).toBe("Module description.");
337
- });
338
- });
339
- it("file with @summary but no free-text has null description", () => {
340
- const result = parseFileSummaries(fixture("summary-only.ts"));
341
- expect(result.hasFileJsdoc).toBe(true);
342
- expect(result.summary).toBe("Summary without description");
343
- expect(result.description).toBeNull();
344
- });
345
- it("literal @ in prose does not start a new tag", () => {
346
- const result = parseFileSummaries(fixture("email-in-prose.ts"));
347
- expect(result.hasFileJsdoc).toBe(true);
348
- expect(result.summary).toBe("Email module summary");
349
- expect(result.description).toBe(
350
- "Contact user@example.com for more info about this module.",
351
- );
352
- });
353
- });