nestjs-openapi-parser 0.0.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.
Files changed (44) hide show
  1. package/README.md +213 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +54 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/config/defaults.d.ts +5 -0
  6. package/dist/config/defaults.js +14 -0
  7. package/dist/config/defaults.js.map +1 -0
  8. package/dist/config/index.d.ts +4 -0
  9. package/dist/config/index.js +24 -0
  10. package/dist/config/index.js.map +1 -0
  11. package/dist/config/loader.d.ts +11 -0
  12. package/dist/config/loader.js +160 -0
  13. package/dist/config/loader.js.map +1 -0
  14. package/dist/config/types.d.ts +139 -0
  15. package/dist/config/types.js +8 -0
  16. package/dist/config/types.js.map +1 -0
  17. package/dist/lib.d.ts +12 -0
  18. package/dist/lib.js +22 -0
  19. package/dist/lib.js.map +1 -0
  20. package/dist/parser/ast-index.d.ts +38 -0
  21. package/dist/parser/ast-index.js +124 -0
  22. package/dist/parser/ast-index.js.map +1 -0
  23. package/dist/parser/index.d.ts +20 -0
  24. package/dist/parser/index.js +95 -0
  25. package/dist/parser/index.js.map +1 -0
  26. package/dist/parser/path-builder.d.ts +87 -0
  27. package/dist/parser/path-builder.js +464 -0
  28. package/dist/parser/path-builder.js.map +1 -0
  29. package/dist/parser/schema-builder.d.ts +70 -0
  30. package/dist/parser/schema-builder.js +355 -0
  31. package/dist/parser/schema-builder.js.map +1 -0
  32. package/dist/parser/tags.d.ts +61 -0
  33. package/dist/parser/tags.js +163 -0
  34. package/dist/parser/tags.js.map +1 -0
  35. package/dist/types/openapi.d.ts +42 -0
  36. package/dist/types/openapi.js +3 -0
  37. package/dist/types/openapi.js.map +1 -0
  38. package/dist/validate.d.ts +13 -0
  39. package/dist/validate.js +30 -0
  40. package/dist/validate.js.map +1 -0
  41. package/docs/configuration.md +195 -0
  42. package/docs/library-usage.md +40 -0
  43. package/docs/parser.md +148 -0
  44. package/package.json +54 -0
@@ -0,0 +1,355 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SchemaBuilder = void 0;
4
+ const ts_morph_1 = require("ts-morph");
5
+ const ast_index_1 = require("./ast-index");
6
+ const tags_1 = require("./tags");
7
+ /**
8
+ * Converts TypeScript classes (entities & DTOs) into OpenAPI `components.schemas`.
9
+ * Handles:
10
+ * - required derived from `@IsOptional()` / `?` (configurable)
11
+ * - `@Exclude()` properties omitted (configurable)
12
+ * - union object types -> `oneOf`, string-literal unions -> enum
13
+ * - `PartialType / PickType / OmitType / IntersectionType` heritage
14
+ */
15
+ class SchemaBuilder {
16
+ index;
17
+ schemas = {};
18
+ pending = new Set();
19
+ done = new Set();
20
+ activeScopes;
21
+ knownScopes;
22
+ constructor(index, options = {}) {
23
+ this.index = index;
24
+ this.activeScopes = options.activeScopes ?? new Set();
25
+ this.knownScopes = options.knownScopes;
26
+ }
27
+ /** Register a reference to a class schema and return the `$ref` fragment. */
28
+ registerRef(name) {
29
+ if (!this.index.hasClass(name))
30
+ return { type: 'object' };
31
+ if (!this.done.has(name))
32
+ this.pending.add(name);
33
+ return { $ref: `#/components/schemas/${name}` };
34
+ }
35
+ /** Process the queue until no schema remains to build. */
36
+ build() {
37
+ while (this.pending.size) {
38
+ const name = this.pending.values().next().value;
39
+ this.pending.delete(name);
40
+ if (this.done.has(name))
41
+ continue;
42
+ this.done.add(name);
43
+ const clazz = this.index.getClass(name);
44
+ if (!clazz)
45
+ continue;
46
+ const classScopes = (0, tags_1.getScopes)((0, tags_1.getTags)(clazz));
47
+ if (!(0, tags_1.isVisible)(classScopes, this.activeScopes)) {
48
+ throw new Error(`Scope conflict: class "${name}" is reached by the spec but has @Scope ${formatScopes(classScopes)} ` +
49
+ `which doesn't match the active scopes ${formatScopes(this.activeScopes)}. ` +
50
+ `Add a matching scope to --scope/config.scopes, or hide whatever referenced it.`);
51
+ }
52
+ const members = this.buildMembers(clazz);
53
+ const schema = { type: 'object', properties: members.properties };
54
+ if (members.required.length)
55
+ schema.required = members.required;
56
+ const rawDesc = clazz.getJsDocs()[0]?.getCommentText();
57
+ const desc = rawDesc
58
+ ? (0, tags_1.filterScopedComments)(rawDesc, this.activeScopes, {
59
+ itemPath: name,
60
+ knownScopes: this.knownScopes,
61
+ })
62
+ : undefined;
63
+ if (desc)
64
+ schema.description = desc;
65
+ this.schemas[name] = schema;
66
+ }
67
+ }
68
+ getSchemas() {
69
+ return this.schemas;
70
+ }
71
+ /** Public entry to map an arbitrary type to an OpenAPI schema fragment. */
72
+ typeToSchema(type) {
73
+ return this.schemaForType(type);
74
+ }
75
+ /** Flatten a class's properties (own + inherited / mapped-type heritage). */
76
+ buildMembers(clazz) {
77
+ const base = clazz.getBaseClass();
78
+ let inherited = { properties: {}, required: [] };
79
+ if (base) {
80
+ inherited = this.buildMembers(base);
81
+ }
82
+ else {
83
+ const ext = clazz.getExtends();
84
+ if (ext)
85
+ inherited = this.resolveHeritage(ext.getExpression());
86
+ }
87
+ return this.mergeMembers(inherited, this.buildOwnMembers(clazz));
88
+ }
89
+ buildOwnMembers(clazz) {
90
+ const properties = {};
91
+ const required = [];
92
+ const excludeDecorator = this.index.excludeDecorator;
93
+ for (const prop of clazz.getInstanceProperties()) {
94
+ if (!ts_morph_1.Node.isPropertyDeclaration(prop))
95
+ continue;
96
+ if (prop.getDecorator(excludeDecorator))
97
+ continue;
98
+ if (!(0, tags_1.isVisible)((0, tags_1.getScopes)((0, tags_1.getTags)(prop)), this.activeScopes))
99
+ continue;
100
+ const name = prop.getName();
101
+ const schema = this.schemaForType(prop.getType());
102
+ this.applyValidatorConstraints(schema, prop);
103
+ const rawDesc = prop.getJsDocs()[0]?.getCommentText();
104
+ const desc = rawDesc
105
+ ? (0, tags_1.filterScopedComments)(rawDesc, this.activeScopes, {
106
+ itemPath: `${clazz.getName() ?? '<anon>'}.${name}`,
107
+ knownScopes: this.knownScopes,
108
+ })
109
+ : undefined;
110
+ properties[name] = desc ? withDescription(schema, desc) : schema;
111
+ if (!this.index.isOptionalProperty(prop))
112
+ required.push(name);
113
+ }
114
+ return { properties, required };
115
+ }
116
+ /** Resolve `PartialType() / PickType() / OmitType() / IntersectionType()` heritage. */
117
+ resolveHeritage(expr) {
118
+ if (ts_morph_1.Node.isIdentifier(expr)) {
119
+ const cls = this.index.getClass(expr.getText());
120
+ return cls ? this.buildMembers(cls) : { properties: {}, required: [] };
121
+ }
122
+ if (ts_morph_1.Node.isCallExpression(expr)) {
123
+ const fnName = expr.getExpression().getText();
124
+ const args = expr.getArguments();
125
+ if (fnName === 'IntersectionType') {
126
+ let merged = { properties: {}, required: [] };
127
+ for (const arg of args)
128
+ merged = this.mergeMembers(merged, this.resolveHeritage(arg));
129
+ return merged;
130
+ }
131
+ const inner = args.length ? this.resolveHeritage(args[0]) : { properties: {}, required: [] };
132
+ if (fnName === 'PartialType')
133
+ return { properties: inner.properties, required: [] };
134
+ if (fnName === 'PickType')
135
+ return this.pick(inner, this.parseStringArray(args[1]));
136
+ if (fnName === 'OmitType')
137
+ return this.omit(inner, this.parseStringArray(args[1]));
138
+ return inner;
139
+ }
140
+ return { properties: {}, required: [] };
141
+ }
142
+ schemaForType(type) {
143
+ if (type.isString())
144
+ return { type: 'string' };
145
+ if (type.isNumber())
146
+ return { type: 'number' };
147
+ if (type.isBoolean())
148
+ return { type: 'boolean' };
149
+ const symbolName = ast_index_1.AstIndex.symbolName(type);
150
+ if (symbolName === 'Date')
151
+ return { type: 'string', format: 'date-time' };
152
+ if (type.isArray()) {
153
+ const element = type.getArrayElementType();
154
+ return { type: 'array', items: element ? this.schemaForType(element) : {} };
155
+ }
156
+ if (symbolName && this.index.hasEnum(symbolName)) {
157
+ return this.enumSchema(symbolName);
158
+ }
159
+ if (type.isUnion()) {
160
+ const members = type.getUnionTypes().filter((t) => !t.isUndefined() && !t.isNull());
161
+ if (members.length === 1)
162
+ return this.schemaForType(members[0]);
163
+ if (members.length && members.every((t) => t.isStringLiteral())) {
164
+ return { type: 'string', enum: members.map((t) => t.getLiteralValue()) };
165
+ }
166
+ const objectMembers = members.filter((t) => {
167
+ const n = ast_index_1.AstIndex.symbolName(t);
168
+ return n && this.index.hasClass(n);
169
+ });
170
+ if (members.length > 0 && objectMembers.length === members.length) {
171
+ return { oneOf: members.map((t) => this.registerRef(ast_index_1.AstIndex.symbolName(t))) };
172
+ }
173
+ return { type: 'object' };
174
+ }
175
+ if (symbolName && this.index.hasClass(symbolName)) {
176
+ return this.registerRef(symbolName);
177
+ }
178
+ return { type: 'object' };
179
+ }
180
+ /**
181
+ * Build the schema for a named TS enum, deriving `type` from the member
182
+ * values rather than assuming strings:
183
+ * - all strings -> `string`
184
+ * - all integers -> `integer`
185
+ * - all numbers (some non-integer) -> `number`
186
+ * - mixed string/number -> `type` omitted (no single OpenAPI type fits)
187
+ */
188
+ enumSchema(name) {
189
+ const values = this.index.getEnumValues(name) ?? [];
190
+ if (values.length === 0)
191
+ return { type: 'string', enum: values };
192
+ if (values.every((v) => typeof v === 'number')) {
193
+ const type = values.every((v) => Number.isInteger(v)) ? 'integer' : 'number';
194
+ return { type, enum: values };
195
+ }
196
+ if (values.every((v) => typeof v === 'string')) {
197
+ return { type: 'string', enum: values };
198
+ }
199
+ return { enum: values };
200
+ }
201
+ /**
202
+ * Merge class-validator constraints from a property's decorators into its
203
+ * schema. Unknown decorators are ignored. A `$ref` is left untouched (its
204
+ * siblings are ignored by OpenAPI 3.0, so constraints don't belong on it).
205
+ *
206
+ * - `@Min/@Max` -> `minimum` / `maximum`
207
+ * - `@MinLength/@MaxLength` -> `minLength` / `maxLength`
208
+ * - `@Length(min, max)` -> `minLength` + `maxLength`
209
+ * - `@ArrayMinSize/@ArrayMaxSize` -> `minItems` / `maxItems`
210
+ * - `@IsEmail/@IsUrl/@IsUUID/@IsDateString` -> `format`
211
+ * - `@Matches(/re/)` -> `pattern`
212
+ * - `@IsInt` -> narrows `number` to `integer`
213
+ * - `@IsPositive/@IsNegative` -> exclusive `minimum` / `maximum` of 0
214
+ */
215
+ applyValidatorConstraints(schema, prop) {
216
+ if ('$ref' in schema)
217
+ return;
218
+ for (const decorator of prop.getDecorators()) {
219
+ const args = decorator.getArguments();
220
+ const setNum = (key, value) => {
221
+ if (value !== undefined)
222
+ schema[key] = value;
223
+ };
224
+ switch (decorator.getName()) {
225
+ case 'Min':
226
+ setNum('minimum', literalNumber(args[0]));
227
+ break;
228
+ case 'Max':
229
+ setNum('maximum', literalNumber(args[0]));
230
+ break;
231
+ case 'MinLength':
232
+ setNum('minLength', literalNumber(args[0]));
233
+ break;
234
+ case 'MaxLength':
235
+ setNum('maxLength', literalNumber(args[0]));
236
+ break;
237
+ case 'Length':
238
+ setNum('minLength', literalNumber(args[0]));
239
+ setNum('maxLength', literalNumber(args[1]));
240
+ break;
241
+ case 'ArrayMinSize':
242
+ setNum('minItems', literalNumber(args[0]));
243
+ break;
244
+ case 'ArrayMaxSize':
245
+ setNum('maxItems', literalNumber(args[0]));
246
+ break;
247
+ case 'IsEmail':
248
+ schema.format = 'email';
249
+ break;
250
+ case 'IsUrl':
251
+ schema.format = 'uri';
252
+ break;
253
+ case 'IsUUID':
254
+ schema.format = 'uuid';
255
+ break;
256
+ case 'IsDateString':
257
+ schema.format = 'date-time';
258
+ break;
259
+ case 'IsInt':
260
+ if (schema.type === 'number')
261
+ schema.type = 'integer';
262
+ break;
263
+ case 'IsPositive':
264
+ schema.minimum = 0;
265
+ schema.exclusiveMinimum = true;
266
+ break;
267
+ case 'IsNegative':
268
+ schema.maximum = 0;
269
+ schema.exclusiveMaximum = true;
270
+ break;
271
+ case 'Matches': {
272
+ const pattern = regexLiteralPattern(args[0]);
273
+ if (pattern !== undefined)
274
+ schema.pattern = pattern;
275
+ break;
276
+ }
277
+ }
278
+ }
279
+ }
280
+ mergeMembers(a, b) {
281
+ const properties = { ...a.properties, ...b.properties };
282
+ const required = [...new Set([...a.required, ...b.required])].filter((k) => k in properties);
283
+ return { properties, required };
284
+ }
285
+ pick(members, keys) {
286
+ const properties = {};
287
+ for (const key of keys)
288
+ if (key in members.properties)
289
+ properties[key] = members.properties[key];
290
+ return { properties, required: members.required.filter((k) => keys.includes(k)) };
291
+ }
292
+ omit(members, keys) {
293
+ const properties = {};
294
+ for (const key of Object.keys(members.properties)) {
295
+ if (!keys.includes(key))
296
+ properties[key] = members.properties[key];
297
+ }
298
+ return { properties, required: members.required.filter((k) => !keys.includes(k)) };
299
+ }
300
+ parseStringArray(arg) {
301
+ if (!arg)
302
+ return [];
303
+ let node = arg;
304
+ if (ts_morph_1.Node.isAsExpression(node))
305
+ node = node.getExpression();
306
+ if (ts_morph_1.Node.isArrayLiteralExpression(node)) {
307
+ return node
308
+ .getElements()
309
+ .map((el) => ts_morph_1.Node.isStringLiteral(el) ? el.getLiteralValue() : el.getText().replace(/['"]/g, ''));
310
+ }
311
+ return [];
312
+ }
313
+ }
314
+ exports.SchemaBuilder = SchemaBuilder;
315
+ function formatScopes(scopes) {
316
+ return scopes.size === 0 ? '{}' : `{${[...scopes].join(', ')}}`;
317
+ }
318
+ /** A numeric decorator argument, supporting a leading unary `-`/`+` (e.g. `@Min(-1)`). */
319
+ function literalNumber(arg) {
320
+ if (!arg)
321
+ return undefined;
322
+ if (ts_morph_1.Node.isNumericLiteral(arg))
323
+ return arg.getLiteralValue();
324
+ if (ts_morph_1.Node.isPrefixUnaryExpression(arg)) {
325
+ const operand = arg.getOperand();
326
+ if (ts_morph_1.Node.isNumericLiteral(operand)) {
327
+ const value = operand.getLiteralValue();
328
+ return arg.getOperatorToken() === ts_morph_1.SyntaxKind.MinusToken ? -value : value;
329
+ }
330
+ }
331
+ return undefined;
332
+ }
333
+ /** The pattern of a `@Matches(...)` argument — a regex literal `/re/flags` or a string. */
334
+ function regexLiteralPattern(arg) {
335
+ if (!arg)
336
+ return undefined;
337
+ if (ts_morph_1.Node.isStringLiteral(arg))
338
+ return arg.getLiteralValue();
339
+ const match = /^\/(.*)\/[dgimsuy]*$/s.exec(arg.getText());
340
+ return match ? match[1] : undefined;
341
+ }
342
+ /**
343
+ * Attach a `description` to a property schema. A `$ref` is a Reference Object
344
+ * whose sibling keys are ignored in OpenAPI 3.0, so a bare `$ref` is wrapped in
345
+ * `allOf` (a normal Schema Object) so the description is actually honored. Any
346
+ * other schema takes the description directly as a sibling.
347
+ */
348
+ function withDescription(schema, description) {
349
+ if ('$ref' in schema) {
350
+ return { allOf: [schema], description };
351
+ }
352
+ schema.description = description;
353
+ return schema;
354
+ }
355
+ //# sourceMappingURL=schema-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-builder.js","sourceRoot":"","sources":["../../src/parser/schema-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import type { Node } from 'ts-morph';
2
+ /** Tag name → values (one entry per `@TagName` occurrence in the node's JSDoc). */
3
+ export type TagBag = Record<string, string[]>;
4
+ /**
5
+ * Extract all custom JSDoc tags on a node.
6
+ *
7
+ * Only tags at line start (after the JSDoc `* ` prefix) are recognized — inline
8
+ * mentions like `Some text with @Scope inline` are description, not tags.
9
+ * That behavior comes from the TypeScript JSDoc parser; we just consume it.
10
+ *
11
+ * The value is taken from the SAME line as `@TagName`. ts-morph treats lines
12
+ * after a tag as continuation of the tag's body until the next tag, but we
13
+ * want subsequent comment lines to remain plain description — so we read only
14
+ * the first line.
15
+ */
16
+ export declare function getTags(node: Node): TagBag;
17
+ /**
18
+ * Resolve the `@Scope` tag values on a node into a flat set of scope names.
19
+ * Accepts comma-separated lists with optional whitespace
20
+ * (`@Scope internal,admin`, `@Scope internal, admin`) and multiple occurrences
21
+ * (`@Scope internal` on one line and `@Scope admin` on another).
22
+ */
23
+ export declare function getScopes(bag: TagBag): Set<string>;
24
+ /**
25
+ * Decide whether an item is visible under the active scopes.
26
+ *
27
+ * - Untagged items (`itemScopes` empty) are always visible.
28
+ * - When no scope is active, only untagged items are visible.
29
+ * - Otherwise, visible iff at least one of the item's scopes is active.
30
+ */
31
+ export declare function isVisible(itemScopes: Set<string>, activeScopes: Set<string>): boolean;
32
+ /**
33
+ * Normalize an `--scope a,b --scope c` style CLI input (or a `scopes` config
34
+ * array) into a flat string list — comma-split, trimmed, falsy filtered.
35
+ */
36
+ export declare function parseScopeList(raw: string | string[] | undefined): string[];
37
+ /**
38
+ * Filter `<scope>…</scope>` fragments inside a JSDoc description.
39
+ *
40
+ * - Untagged text passes through unchanged.
41
+ * - `<X>…</X>` keeps its inner text when `X ∈ activeScopes`; otherwise the
42
+ * whole block (open tag → close tag) is removed.
43
+ * - The remaining text is normalized: lines that contained only an open/close
44
+ * tag are dropped (including their newline), runs of 3+ newlines collapse
45
+ * to 2, and the result is trimmed.
46
+ * - Nested fragments, mismatched close tags, and unclosed open tags throw.
47
+ *
48
+ * Only names that are *known scopes* are treated as fragment delimiters. Pass
49
+ * the project's scope vocabulary via `ctx.knownScopes`; any other angle-bracket
50
+ * token — generics in prose (`Array<string>`), placeholders (`<id>`, `<token>`),
51
+ * inline HTML (`<b>…</b>`) — passes through verbatim and never throws. When
52
+ * `ctx.knownScopes` is omitted, every `<name>` is treated as a fragment (legacy
53
+ * behavior, retained for direct callers and unit tests).
54
+ *
55
+ * The optional `ctx.itemPath` (e.g. `"User.email"`) is included in the error
56
+ * message so misconfigured comments are easy to locate.
57
+ */
58
+ export declare function filterScopedComments(text: string, activeScopes: Set<string>, ctx?: {
59
+ itemPath?: string;
60
+ knownScopes?: Set<string>;
61
+ }): string;
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTags = getTags;
4
+ exports.getScopes = getScopes;
5
+ exports.isVisible = isVisible;
6
+ exports.parseScopeList = parseScopeList;
7
+ exports.filterScopedComments = filterScopedComments;
8
+ function hasJsDocs(node) {
9
+ return typeof node.getJsDocs === 'function';
10
+ }
11
+ /**
12
+ * Extract all custom JSDoc tags on a node.
13
+ *
14
+ * Only tags at line start (after the JSDoc `* ` prefix) are recognized — inline
15
+ * mentions like `Some text with @Scope inline` are description, not tags.
16
+ * That behavior comes from the TypeScript JSDoc parser; we just consume it.
17
+ *
18
+ * The value is taken from the SAME line as `@TagName`. ts-morph treats lines
19
+ * after a tag as continuation of the tag's body until the next tag, but we
20
+ * want subsequent comment lines to remain plain description — so we read only
21
+ * the first line.
22
+ */
23
+ function getTags(node) {
24
+ if (!hasJsDocs(node))
25
+ return {};
26
+ const bag = {};
27
+ for (const jsdoc of node.getJsDocs()) {
28
+ for (const tag of jsdoc.getTags()) {
29
+ const name = tag.getTagName();
30
+ const value = (tag.getCommentText() ?? '').split('\n')[0].trim();
31
+ (bag[name] ??= []).push(value);
32
+ }
33
+ }
34
+ return bag;
35
+ }
36
+ /**
37
+ * Resolve the `@Scope` tag values on a node into a flat set of scope names.
38
+ * Accepts comma-separated lists with optional whitespace
39
+ * (`@Scope internal,admin`, `@Scope internal, admin`) and multiple occurrences
40
+ * (`@Scope internal` on one line and `@Scope admin` on another).
41
+ */
42
+ function getScopes(bag) {
43
+ return new Set((bag.Scope ?? []).flatMap((v) => v
44
+ .split(',')
45
+ .map((s) => s.trim())
46
+ .filter(Boolean)));
47
+ }
48
+ /**
49
+ * Decide whether an item is visible under the active scopes.
50
+ *
51
+ * - Untagged items (`itemScopes` empty) are always visible.
52
+ * - When no scope is active, only untagged items are visible.
53
+ * - Otherwise, visible iff at least one of the item's scopes is active.
54
+ */
55
+ function isVisible(itemScopes, activeScopes) {
56
+ if (itemScopes.size === 0)
57
+ return true;
58
+ if (activeScopes.size === 0)
59
+ return false;
60
+ for (const s of itemScopes)
61
+ if (activeScopes.has(s))
62
+ return true;
63
+ return false;
64
+ }
65
+ /**
66
+ * Normalize an `--scope a,b --scope c` style CLI input (or a `scopes` config
67
+ * array) into a flat string list — comma-split, trimmed, falsy filtered.
68
+ */
69
+ function parseScopeList(raw) {
70
+ if (raw === undefined)
71
+ return [];
72
+ const items = Array.isArray(raw) ? raw : [raw];
73
+ return items.flatMap((s) => s
74
+ .split(',')
75
+ .map((p) => p.trim())
76
+ .filter(Boolean));
77
+ }
78
+ // Matches an element-style open or close tag: <name> or </name>. The name must
79
+ // look like a scope identifier — letters/digits/underscore/hyphen, leading
80
+ // letter. Whether a match is an actual scope fragment (vs. literal prose) is
81
+ // decided downstream against the known-scope vocabulary.
82
+ const FRAGMENT_TAG = /<\/?([A-Za-z][A-Za-z0-9_-]*)>/g;
83
+ /**
84
+ * Filter `<scope>…</scope>` fragments inside a JSDoc description.
85
+ *
86
+ * - Untagged text passes through unchanged.
87
+ * - `<X>…</X>` keeps its inner text when `X ∈ activeScopes`; otherwise the
88
+ * whole block (open tag → close tag) is removed.
89
+ * - The remaining text is normalized: lines that contained only an open/close
90
+ * tag are dropped (including their newline), runs of 3+ newlines collapse
91
+ * to 2, and the result is trimmed.
92
+ * - Nested fragments, mismatched close tags, and unclosed open tags throw.
93
+ *
94
+ * Only names that are *known scopes* are treated as fragment delimiters. Pass
95
+ * the project's scope vocabulary via `ctx.knownScopes`; any other angle-bracket
96
+ * token — generics in prose (`Array<string>`), placeholders (`<id>`, `<token>`),
97
+ * inline HTML (`<b>…</b>`) — passes through verbatim and never throws. When
98
+ * `ctx.knownScopes` is omitted, every `<name>` is treated as a fragment (legacy
99
+ * behavior, retained for direct callers and unit tests).
100
+ *
101
+ * The optional `ctx.itemPath` (e.g. `"User.email"`) is included in the error
102
+ * message so misconfigured comments are easy to locate.
103
+ */
104
+ function filterScopedComments(text, activeScopes, ctx = {}) {
105
+ const where = ctx.itemPath ? ` at ${ctx.itemPath}` : '';
106
+ const known = ctx.knownScopes;
107
+ const isScopeTag = (name) => known === undefined || known.has(name);
108
+ let currentScope;
109
+ let keep = true;
110
+ let out = '';
111
+ let cursor = 0;
112
+ FRAGMENT_TAG.lastIndex = 0;
113
+ for (let m = FRAGMENT_TAG.exec(text); m !== null; m = FRAGMENT_TAG.exec(text)) {
114
+ const before = text.slice(cursor, m.index);
115
+ if (keep)
116
+ out += before;
117
+ cursor = m.index + m[0].length;
118
+ const name = m[1];
119
+ const isClose = m[0].startsWith('</');
120
+ // Not a scope name — ordinary prose. Emit it verbatim (when we're keeping
121
+ // the surrounding text) and leave the fragment state untouched.
122
+ if (!isScopeTag(name)) {
123
+ if (keep)
124
+ out += m[0];
125
+ continue;
126
+ }
127
+ if (!isClose) {
128
+ if (currentScope !== undefined) {
129
+ throw new Error(`Nested scope fragments are not allowed${where}: <${name}> inside <${currentScope}>.`);
130
+ }
131
+ currentScope = name;
132
+ keep = activeScopes.has(name);
133
+ }
134
+ else {
135
+ if (currentScope === undefined) {
136
+ throw new Error(`Unmatched closing scope tag </${name}>${where}.`);
137
+ }
138
+ if (currentScope !== name) {
139
+ throw new Error(`Mismatched scope tag </${name}>${where} (expected </${currentScope}>).`);
140
+ }
141
+ currentScope = undefined;
142
+ keep = true;
143
+ }
144
+ }
145
+ if (currentScope !== undefined) {
146
+ throw new Error(`Unclosed scope fragment <${currentScope}>${where}.`);
147
+ }
148
+ if (keep)
149
+ out += text.slice(cursor);
150
+ return normalizeFiltered(out);
151
+ }
152
+ function normalizeFiltered(text) {
153
+ // Drop lines whose remaining content is only whitespace AND that came from a
154
+ // removed tag — heuristic: any line that, after trim, is empty stays as a
155
+ // blank line, but we then collapse runs.
156
+ const noBlankLineRuns = text
157
+ .split('\n')
158
+ .map((line) => (line.trim() === '' ? '' : line))
159
+ .join('\n')
160
+ .replace(/\n{3,}/g, '\n\n');
161
+ return noBlankLineRuns.trim();
162
+ }
163
+ //# sourceMappingURL=tags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags.js","sourceRoot":"","sources":["../../src/parser/tags.ts"],"names":[],"mappings":";;AAyBA,0BAWC;AAQD,8BASC;AASD,8BAKC;AAMD,wCASC;AA6BD,oDAwDC;AA9JD,SAAS,SAAS,CAAC,IAAU;IAC3B,OAAO,OAAQ,IAA+B,CAAC,SAAS,KAAK,UAAU,CAAC;AAC1E,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,OAAO,CAAC,IAAU;IAChC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,MAAM,GAAG,GAAW,EAAE,CAAC;IACvB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;QACrC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACjE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,SAAgB,SAAS,CAAC,GAAW;IACnC,OAAO,IAAI,GAAG,CACZ,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9B,CAAC;SACE,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CACnB,CACF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,SAAS,CAAC,UAAuB,EAAE,YAAyB;IAC1E,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,UAAU;QAAE,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IACjE,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAAC,GAAkC;IAC/D,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CACzB,CAAC;SACE,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CACnB,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,2EAA2E;AAC3E,6EAA6E;AAC7E,yDAAyD;AACzD,MAAM,YAAY,GAAG,gCAAgC,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,oBAAoB,CAClC,IAAY,EACZ,YAAyB,EACzB,MAAwD,EAAE;IAE1D,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACxD,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC;IAC9B,MAAM,UAAU,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAErF,IAAI,YAAgC,CAAC;IACrC,IAAI,IAAI,GAAG,IAAI,CAAC;IAChB,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,IAAI;YAAE,GAAG,IAAI,MAAM,CAAC;QACxB,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAE/B,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAClB,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAEtC,0EAA0E;QAC1E,gEAAgE;QAChE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,IAAI,IAAI;gBAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CACb,yCAAyC,KAAK,MAAM,IAAI,aAAa,YAAY,IAAI,CACtF,CAAC;YACJ,CAAC;YACD,YAAY,GAAG,IAAI,CAAC;YACpB,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACN,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC;YACrE,CAAC;YACD,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,IAAI,KAAK,gBAAgB,YAAY,KAAK,CAAC,CAAC;YAC5F,CAAC;YACD,YAAY,GAAG,SAAS,CAAC;YACzB,IAAI,GAAG,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,4BAA4B,YAAY,IAAI,KAAK,GAAG,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,IAAI;QAAE,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEpC,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY;IACrC,6EAA6E;IAC7E,0EAA0E;IAC1E,yCAAyC;IACzC,MAAM,eAAe,GAAG,IAAI;SACzB,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SAC/C,IAAI,CAAC,IAAI,CAAC;SACV,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,eAAe,CAAC,IAAI,EAAE,CAAC;AAChC,CAAC"}
@@ -0,0 +1,42 @@
1
+ export type OpenApiSchema = Record<string, unknown>;
2
+ export interface OpenApiServer {
3
+ url: string;
4
+ description?: string;
5
+ variables?: Record<string, {
6
+ default: string;
7
+ enum?: string[];
8
+ description?: string;
9
+ }>;
10
+ }
11
+ export interface OpenApiInfo {
12
+ title: string;
13
+ version: string;
14
+ description?: string;
15
+ termsOfService?: string;
16
+ contact?: {
17
+ name?: string;
18
+ url?: string;
19
+ email?: string;
20
+ };
21
+ license?: {
22
+ name: string;
23
+ url?: string;
24
+ };
25
+ }
26
+ export type OpenApiSecurityScheme = Record<string, unknown>;
27
+ export type OpenApiSecurityRequirement = Record<string, string[]>;
28
+ export interface OpenApiDocument {
29
+ openapi: string;
30
+ info: OpenApiInfo;
31
+ servers?: OpenApiServer[];
32
+ paths: Record<string, Record<string, unknown>>;
33
+ components?: {
34
+ schemas?: Record<string, OpenApiSchema>;
35
+ securitySchemes?: Record<string, OpenApiSecurityScheme>;
36
+ };
37
+ security?: OpenApiSecurityRequirement[];
38
+ tags?: {
39
+ name: string;
40
+ description?: string;
41
+ }[];
42
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=openapi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../src/types/openapi.ts"],"names":[],"mappings":""}