genoc 0.1.0

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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +233 -0
  3. package/dist/analyzer/naming.d.ts +24 -0
  4. package/dist/analyzer/naming.js +122 -0
  5. package/dist/analyzer/path-analyzer.d.ts +53 -0
  6. package/dist/analyzer/path-analyzer.js +222 -0
  7. package/dist/analyzer/schema-mapper.d.ts +48 -0
  8. package/dist/analyzer/schema-mapper.js +435 -0
  9. package/dist/cli/app.d.ts +9 -0
  10. package/dist/cli/app.js +60 -0
  11. package/dist/cli/errors.d.ts +3 -0
  12. package/dist/cli/errors.js +6 -0
  13. package/dist/cli/impl.d.ts +3 -0
  14. package/dist/cli/impl.js +45 -0
  15. package/dist/cli/index.d.ts +2 -0
  16. package/dist/cli/index.js +5 -0
  17. package/dist/generator/client-generator.d.ts +21 -0
  18. package/dist/generator/client-generator.js +287 -0
  19. package/dist/generator/contracts-generator.d.ts +16 -0
  20. package/dist/generator/contracts-generator.js +525 -0
  21. package/dist/generator/error-types.d.ts +24 -0
  22. package/dist/generator/error-types.js +94 -0
  23. package/dist/generator/method-generator.d.ts +9 -0
  24. package/dist/generator/method-generator.js +249 -0
  25. package/dist/index.d.ts +7 -0
  26. package/dist/index.js +8 -0
  27. package/dist/parser/ref-resolver.d.ts +24 -0
  28. package/dist/parser/ref-resolver.js +119 -0
  29. package/dist/parser/spec-reader.d.ts +4 -0
  30. package/dist/parser/spec-reader.js +116 -0
  31. package/dist/parser/validators.d.ts +7 -0
  32. package/dist/parser/validators.js +79 -0
  33. package/dist/parser/version/index.d.ts +18 -0
  34. package/dist/parser/version/index.js +16 -0
  35. package/dist/parser/version/normalized-spec.d.ts +199 -0
  36. package/dist/parser/version/normalized-spec.js +1 -0
  37. package/dist/parser/version/registry.d.ts +28 -0
  38. package/dist/parser/version/registry.js +44 -0
  39. package/dist/parser/version/v3.0/index.d.ts +3 -0
  40. package/dist/parser/version/v3.0/index.js +3 -0
  41. package/dist/parser/version/v3.0/normalizer.d.ts +15 -0
  42. package/dist/parser/version/v3.0/normalizer.js +389 -0
  43. package/dist/parser/version/v3.0/strategy.d.ts +27 -0
  44. package/dist/parser/version/v3.0/strategy.js +96 -0
  45. package/dist/parser/version/v3.0/validator.d.ts +13 -0
  46. package/dist/parser/version/v3.0/validator.js +117 -0
  47. package/dist/parser/version/v3.1/index.d.ts +1 -0
  48. package/dist/parser/version/v3.1/index.js +1 -0
  49. package/dist/parser/version/v3.1/strategy.d.ts +42 -0
  50. package/dist/parser/version/v3.1/strategy.js +513 -0
  51. package/dist/parser/version/v3.2/index.d.ts +4 -0
  52. package/dist/parser/version/v3.2/index.js +4 -0
  53. package/dist/parser/version/v3.2/strategy.d.ts +39 -0
  54. package/dist/parser/version/v3.2/strategy.js +57 -0
  55. package/dist/parser/version/version-detector.d.ts +4 -0
  56. package/dist/parser/version/version-detector.js +34 -0
  57. package/dist/parser/version/version-strategy.d.ts +31 -0
  58. package/dist/parser/version/version-strategy.js +1 -0
  59. package/dist/types/client.d.ts +25 -0
  60. package/dist/types/client.js +1 -0
  61. package/dist/types/contracts.d.ts +13 -0
  62. package/dist/types/contracts.js +1 -0
  63. package/dist/types/openapi.d.ts +173 -0
  64. package/dist/types/openapi.js +1 -0
  65. package/dist/utils/case.d.ts +5 -0
  66. package/dist/utils/case.js +51 -0
  67. package/dist/utils/generator-helpers.d.ts +23 -0
  68. package/dist/utils/generator-helpers.js +66 -0
  69. package/dist/utils/string.d.ts +34 -0
  70. package/dist/utils/string.js +182 -0
  71. package/dist/utils/url.d.ts +10 -0
  72. package/dist/utils/url.js +40 -0
  73. package/package.json +60 -0
@@ -0,0 +1,27 @@
1
+ import type { ValidationResult } from '../../validators.js';
2
+ import type { NormalizedSpec } from '../normalized-spec.js';
3
+ import type { VersionStrategy } from '../version-strategy.js';
4
+ /**
5
+ * Version strategy for OpenAPI 3.0.x specifications.
6
+ *
7
+ * OpenAPI 3.0 is the original version of the OpenAPI specification and differs
8
+ * from 3.1 in several key ways:
9
+ * - `nullable` keyword (not type arrays with "null")
10
+ * - `exclusiveMinimum`/`exclusiveMaximum` as booleans modifying `minimum`/`maximum`
11
+ * - `$ref` siblings are ignored (not merged)
12
+ * - `example` keyword (not `examples`)
13
+ * - `paths` is required
14
+ */
15
+ export declare class V3_0_VersionStrategy implements VersionStrategy {
16
+ version(): string;
17
+ matches(spec: unknown): boolean;
18
+ normalizeSpec(rawSpec: unknown): NormalizedSpec;
19
+ validateSpec(spec: NormalizedSpec): ValidationResult;
20
+ /**
21
+ * Resolve a $ref within the document. For OpenAPI 3.0, sibling properties
22
+ * alongside `$ref` are ignored — only the $ref target is returned.
23
+ */
24
+ resolveRef(ref: string, doc: unknown, _context?: unknown): unknown;
25
+ getSupportedFeatures(): string[];
26
+ private resolveRefInternal;
27
+ }
@@ -0,0 +1,96 @@
1
+ import { parseJsonPointer } from '../../../utils/url.js';
2
+ import { normalizeSpec30 } from './normalizer.js';
3
+ import { validateSpec30 } from './validator.js';
4
+ const MAX_REF_DEPTH = 10;
5
+ /**
6
+ * Version strategy for OpenAPI 3.0.x specifications.
7
+ *
8
+ * OpenAPI 3.0 is the original version of the OpenAPI specification and differs
9
+ * from 3.1 in several key ways:
10
+ * - `nullable` keyword (not type arrays with "null")
11
+ * - `exclusiveMinimum`/`exclusiveMaximum` as booleans modifying `minimum`/`maximum`
12
+ * - `$ref` siblings are ignored (not merged)
13
+ * - `example` keyword (not `examples`)
14
+ * - `paths` is required
15
+ */
16
+ export class V3_0_VersionStrategy {
17
+ version() {
18
+ return '3.0';
19
+ }
20
+ matches(spec) {
21
+ if (!spec || typeof spec !== 'object' || Array.isArray(spec)) {
22
+ return false;
23
+ }
24
+ const specObj = spec;
25
+ const openapiVersion = specObj.openapi;
26
+ if (typeof openapiVersion === 'string') {
27
+ return openapiVersion.startsWith('3.0');
28
+ }
29
+ return false;
30
+ }
31
+ normalizeSpec(rawSpec) {
32
+ return normalizeSpec30(rawSpec);
33
+ }
34
+ validateSpec(spec) {
35
+ return validateSpec30(spec);
36
+ }
37
+ /**
38
+ * Resolve a $ref within the document. For OpenAPI 3.0, sibling properties
39
+ * alongside `$ref` are ignored — only the $ref target is returned.
40
+ */
41
+ resolveRef(ref, doc, _context) {
42
+ const resolving = new Set();
43
+ return this.resolveRefInternal(ref, doc, resolving, 0);
44
+ }
45
+ getSupportedFeatures() {
46
+ return ['nullable', 'example'];
47
+ }
48
+ resolveRefInternal(ref, doc, resolving, depth) {
49
+ if (ref.startsWith('http://') || ref.startsWith('https://')) {
50
+ throw new Error(`External $ref resolution is not supported: ${ref}`);
51
+ }
52
+ if (!ref.startsWith('#')) {
53
+ throw new Error(`External $ref resolution is not supported: ${ref}`);
54
+ }
55
+ if (depth >= MAX_REF_DEPTH) {
56
+ throw new Error(`Maximum $ref depth (${MAX_REF_DEPTH}) exceeded: ${ref}`);
57
+ }
58
+ if (resolving.has(ref)) {
59
+ const cyclePath = [...resolving, ref].join(' -> ');
60
+ throw new Error(`Circular $ref detected: ${cyclePath}`);
61
+ }
62
+ resolving.add(ref);
63
+ const pointer = ref.slice(1);
64
+ const segments = parseJsonPointer(pointer);
65
+ let current = doc;
66
+ for (const segment of segments) {
67
+ if (current === null || current === undefined) {
68
+ throw new Error(`$ref "${ref}" could not be resolved: segment "${segment}" not found`);
69
+ }
70
+ if (typeof current !== 'object') {
71
+ throw new Error(`$ref "${ref}" could not be resolved: segment "${segment}" is not an object`);
72
+ }
73
+ if (Array.isArray(current)) {
74
+ const index = Number(segment);
75
+ if (Number.isNaN(index)) {
76
+ throw new Error(`$ref "${ref}" could not be resolved: "${segment}" is not a valid array index`);
77
+ }
78
+ current = current[index];
79
+ }
80
+ else {
81
+ current = current[segment];
82
+ }
83
+ }
84
+ if (current === undefined) {
85
+ throw new Error(`$ref "${ref}" could not be resolved`);
86
+ }
87
+ if (current !== null &&
88
+ typeof current === 'object' &&
89
+ !Array.isArray(current) &&
90
+ '$ref' in current) {
91
+ const chainedRef = current.$ref;
92
+ return this.resolveRefInternal(chainedRef, doc, new Set(resolving), depth + 1);
93
+ }
94
+ return current;
95
+ }
96
+ }
@@ -0,0 +1,13 @@
1
+ import type { ValidationResult } from '../../validators.js';
2
+ /**
3
+ * Validate a raw OpenAPI 3.0.x specification.
4
+ *
5
+ * 3.0-specific validation rules:
6
+ * - `openapi` must start with "3.0"
7
+ * - `paths` is required (unlike 3.1 where paths/components/webhooks is flexible)
8
+ * - `info` with `title` and `version` required
9
+ * - Warns about 3.1-only features: `webhooks`, `$schema` in schemas, `type` as array
10
+ * - Accepts `nullable` and `example` (valid in 3.0, not in 3.1)
11
+ * - Errors on `items` as array (3.1-only tuple syntax)
12
+ */
13
+ export declare function validateSpec30(spec: unknown): ValidationResult;
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Validate a raw OpenAPI 3.0.x specification.
3
+ *
4
+ * 3.0-specific validation rules:
5
+ * - `openapi` must start with "3.0"
6
+ * - `paths` is required (unlike 3.1 where paths/components/webhooks is flexible)
7
+ * - `info` with `title` and `version` required
8
+ * - Warns about 3.1-only features: `webhooks`, `$schema` in schemas, `type` as array
9
+ * - Accepts `nullable` and `example` (valid in 3.0, not in 3.1)
10
+ * - Errors on `items` as array (3.1-only tuple syntax)
11
+ */
12
+ export function validateSpec30(spec) {
13
+ const errors = [];
14
+ if (!spec || typeof spec !== 'object' || Array.isArray(spec)) {
15
+ errors.push('Document must be an object');
16
+ return { valid: false, errors };
17
+ }
18
+ const s = spec;
19
+ if (!s.openapi || typeof s.openapi !== 'string') {
20
+ errors.push("OpenAPI specification must have an 'openapi' field with string value");
21
+ }
22
+ else if (!s.openapi.startsWith('3.0')) {
23
+ errors.push(`OpenAPI version must start with '3.0', got: ${s.openapi}`);
24
+ }
25
+ if (!s.info || typeof s.info !== 'object' || Array.isArray(s.info)) {
26
+ errors.push("OpenAPI specification must have an 'info' field with object value");
27
+ }
28
+ else {
29
+ const info = s.info;
30
+ if (!info.title || typeof info.title !== 'string') {
31
+ errors.push("Info object must have a 'title' field with string value");
32
+ }
33
+ if (!info.version || typeof info.version !== 'string') {
34
+ errors.push("Info object must have a 'version' field with string value");
35
+ }
36
+ }
37
+ if (!s.paths || typeof s.paths !== 'object' || Array.isArray(s.paths)) {
38
+ errors.push("OpenAPI 3.0 specification must have a 'paths' field with object value");
39
+ }
40
+ if (s.paths && typeof s.paths === 'object' && !Array.isArray(s.paths)) {
41
+ for (const [pathKey, pathItem] of Object.entries(s.paths)) {
42
+ if (!pathItem || typeof pathItem !== 'object' || Array.isArray(pathItem)) {
43
+ errors.push(`Path item '${pathKey}' must be an object`);
44
+ }
45
+ }
46
+ }
47
+ if (s.components && typeof s.components === 'object' && !Array.isArray(s.components)) {
48
+ const components = s.components;
49
+ if (components.schemas) {
50
+ if (Array.isArray(components.schemas) || typeof components.schemas !== 'object') {
51
+ errors.push("'components.schemas' must be an object");
52
+ }
53
+ else {
54
+ const schemas = components.schemas;
55
+ for (const [key, schema] of Object.entries(schemas)) {
56
+ if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {
57
+ errors.push(`Schema '${key}' must be an object`);
58
+ }
59
+ else {
60
+ validateSchema30(schema, `components.schemas.${key}`, errors);
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ return {
67
+ valid: errors.length === 0,
68
+ errors,
69
+ };
70
+ }
71
+ /**
72
+ * Recursively validate a schema object for 3.0-specific rules.
73
+ * Detects 3.1-only features and reports them as errors.
74
+ */
75
+ function validateSchema30(schema, path, errors) {
76
+ if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {
77
+ return;
78
+ }
79
+ const s = schema;
80
+ if (Array.isArray(s.type)) {
81
+ errors.push(`Schema '${path}' uses 'type' as an array which is a 3.1-only feature`);
82
+ }
83
+ if ('$schema' in s) {
84
+ errors.push(`Schema '${path}' uses '$schema' which is a 3.1-only feature`);
85
+ }
86
+ if (s.items !== undefined && Array.isArray(s.items)) {
87
+ errors.push(`Schema '${path}' uses 'items' as an array (tuple syntax) which is a 3.1-only feature`);
88
+ }
89
+ if (s.properties && typeof s.properties === 'object' && !Array.isArray(s.properties)) {
90
+ for (const [key, prop] of Object.entries(s.properties)) {
91
+ validateSchema30(prop, `${path}.properties.${key}`, errors);
92
+ }
93
+ }
94
+ if (s.items && typeof s.items === 'object' && !Array.isArray(s.items)) {
95
+ validateSchema30(s.items, `${path}.items`, errors);
96
+ }
97
+ if (s.additionalProperties &&
98
+ typeof s.additionalProperties === 'object' &&
99
+ !Array.isArray(s.additionalProperties)) {
100
+ validateSchema30(s.additionalProperties, `${path}.additionalProperties`, errors);
101
+ }
102
+ if (Array.isArray(s.allOf)) {
103
+ s.allOf.forEach((item, i) => {
104
+ validateSchema30(item, `${path}.allOf[${i}]`, errors);
105
+ });
106
+ }
107
+ if (Array.isArray(s.oneOf)) {
108
+ s.oneOf.forEach((item, i) => {
109
+ validateSchema30(item, `${path}.oneOf[${i}]`, errors);
110
+ });
111
+ }
112
+ if (Array.isArray(s.anyOf)) {
113
+ s.anyOf.forEach((item, i) => {
114
+ validateSchema30(item, `${path}.anyOf[${i}]`, errors);
115
+ });
116
+ }
117
+ }
@@ -0,0 +1 @@
1
+ export { V3_1_VersionStrategy } from './strategy.js';
@@ -0,0 +1 @@
1
+ export { V3_1_VersionStrategy } from './strategy.js';
@@ -0,0 +1,42 @@
1
+ import type { ValidationResult } from '../../validators.js';
2
+ import type { NormalizedSpec } from '../normalized-spec.js';
3
+ import type { VersionStrategy } from '../version-strategy.js';
4
+ /**
5
+ * Version strategy for OpenAPI 3.1.x specifications.
6
+ *
7
+ * OpenAPI 3.1 is aligned with JSON Schema 2020-12 and supports:
8
+ * - Type arrays (e.g., `type: ["string", "null"]`)
9
+ * - Sibling properties alongside `$ref`
10
+ * - `exclusiveMinimum`/`exclusiveMaximum` as numbers
11
+ * - `webhooks` at the top level
12
+ */
13
+ export declare class V3_1_VersionStrategy implements VersionStrategy {
14
+ version(): string;
15
+ matches(spec: unknown): boolean;
16
+ /**
17
+ * Normalize a raw OpenAPI 3.1 specification to a consistent format.
18
+ *
19
+ * Schema normalization:
20
+ * - `type: "string"` → `types: ["string"]`
21
+ * - `type: ["string", "null"]` → `types: ["string"]`, `nullable: true`
22
+ * - `example: value` → `examples: [value]` (defensive)
23
+ * - `exclusiveMinimum`/`exclusiveMaximum` extracted as numbers
24
+ * - `format: "binary"` → `fileUpload: { binary: true, base64: false }`
25
+ * - `format: "byte"` → `fileUpload: { binary: false, base64: true }`
26
+ */
27
+ normalizeSpec(rawSpec: unknown): NormalizedSpec;
28
+ validateSpec(spec: NormalizedSpec): ValidationResult;
29
+ /**
30
+ * Resolve a $ref within the document. For OpenAPI 3.1, sibling properties
31
+ * alongside `$ref` are preserved via shallow merge (siblings override target).
32
+ */
33
+ resolveRef(ref: string, doc: unknown, context?: unknown): unknown;
34
+ getSupportedFeatures(): string[];
35
+ private resolveRefInternal;
36
+ private normalizeSchema;
37
+ private normalizePropertyMap;
38
+ private normalizePathItem;
39
+ private normalizeOperation;
40
+ private normalizeContentMap;
41
+ private normalizeParameter;
42
+ }