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.
- package/LICENSE +21 -0
- package/README.md +233 -0
- package/dist/analyzer/naming.d.ts +24 -0
- package/dist/analyzer/naming.js +122 -0
- package/dist/analyzer/path-analyzer.d.ts +53 -0
- package/dist/analyzer/path-analyzer.js +222 -0
- package/dist/analyzer/schema-mapper.d.ts +48 -0
- package/dist/analyzer/schema-mapper.js +435 -0
- package/dist/cli/app.d.ts +9 -0
- package/dist/cli/app.js +60 -0
- package/dist/cli/errors.d.ts +3 -0
- package/dist/cli/errors.js +6 -0
- package/dist/cli/impl.d.ts +3 -0
- package/dist/cli/impl.js +45 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +5 -0
- package/dist/generator/client-generator.d.ts +21 -0
- package/dist/generator/client-generator.js +287 -0
- package/dist/generator/contracts-generator.d.ts +16 -0
- package/dist/generator/contracts-generator.js +525 -0
- package/dist/generator/error-types.d.ts +24 -0
- package/dist/generator/error-types.js +94 -0
- package/dist/generator/method-generator.d.ts +9 -0
- package/dist/generator/method-generator.js +249 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/parser/ref-resolver.d.ts +24 -0
- package/dist/parser/ref-resolver.js +119 -0
- package/dist/parser/spec-reader.d.ts +4 -0
- package/dist/parser/spec-reader.js +116 -0
- package/dist/parser/validators.d.ts +7 -0
- package/dist/parser/validators.js +79 -0
- package/dist/parser/version/index.d.ts +18 -0
- package/dist/parser/version/index.js +16 -0
- package/dist/parser/version/normalized-spec.d.ts +199 -0
- package/dist/parser/version/normalized-spec.js +1 -0
- package/dist/parser/version/registry.d.ts +28 -0
- package/dist/parser/version/registry.js +44 -0
- package/dist/parser/version/v3.0/index.d.ts +3 -0
- package/dist/parser/version/v3.0/index.js +3 -0
- package/dist/parser/version/v3.0/normalizer.d.ts +15 -0
- package/dist/parser/version/v3.0/normalizer.js +389 -0
- package/dist/parser/version/v3.0/strategy.d.ts +27 -0
- package/dist/parser/version/v3.0/strategy.js +96 -0
- package/dist/parser/version/v3.0/validator.d.ts +13 -0
- package/dist/parser/version/v3.0/validator.js +117 -0
- package/dist/parser/version/v3.1/index.d.ts +1 -0
- package/dist/parser/version/v3.1/index.js +1 -0
- package/dist/parser/version/v3.1/strategy.d.ts +42 -0
- package/dist/parser/version/v3.1/strategy.js +513 -0
- package/dist/parser/version/v3.2/index.d.ts +4 -0
- package/dist/parser/version/v3.2/index.js +4 -0
- package/dist/parser/version/v3.2/strategy.d.ts +39 -0
- package/dist/parser/version/v3.2/strategy.js +57 -0
- package/dist/parser/version/version-detector.d.ts +4 -0
- package/dist/parser/version/version-detector.js +34 -0
- package/dist/parser/version/version-strategy.d.ts +31 -0
- package/dist/parser/version/version-strategy.js +1 -0
- package/dist/types/client.d.ts +25 -0
- package/dist/types/client.js +1 -0
- package/dist/types/contracts.d.ts +13 -0
- package/dist/types/contracts.js +1 -0
- package/dist/types/openapi.d.ts +173 -0
- package/dist/types/openapi.js +1 -0
- package/dist/utils/case.d.ts +5 -0
- package/dist/utils/case.js +51 -0
- package/dist/utils/generator-helpers.d.ts +23 -0
- package/dist/utils/generator-helpers.js +66 -0
- package/dist/utils/string.d.ts +34 -0
- package/dist/utils/string.js +182 -0
- package/dist/utils/url.d.ts +10 -0
- package/dist/utils/url.js +40 -0
- package/package.json +60 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ValidationResult } from '../validators.js';
|
|
2
|
+
import type { NormalizedSpec } from './normalized-spec.js';
|
|
3
|
+
/**
|
|
4
|
+
* Version strategy interface for multi-version OpenAPI support
|
|
5
|
+
*/
|
|
6
|
+
export interface VersionStrategy {
|
|
7
|
+
/**
|
|
8
|
+
* Get the supported OpenAPI version
|
|
9
|
+
*/
|
|
10
|
+
version(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Check if this strategy matches the given OpenAPI specification
|
|
13
|
+
*/
|
|
14
|
+
matches(spec: unknown): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Normalize a raw OpenAPI specification to a consistent format
|
|
17
|
+
*/
|
|
18
|
+
normalizeSpec(rawSpec: unknown): NormalizedSpec;
|
|
19
|
+
/**
|
|
20
|
+
* Validate the normalized specification
|
|
21
|
+
*/
|
|
22
|
+
validateSpec(spec: NormalizedSpec): ValidationResult;
|
|
23
|
+
/**
|
|
24
|
+
* Resolve a reference within the document context
|
|
25
|
+
*/
|
|
26
|
+
resolveRef(ref: string, doc: unknown, context?: unknown): unknown;
|
|
27
|
+
/**
|
|
28
|
+
* Get supported features for this version
|
|
29
|
+
*/
|
|
30
|
+
getSupportedFeatures(): string[];
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type MethodNameStrategy = 'path-based' | 'operationId' | 'operationId-with-fallback';
|
|
2
|
+
export type GeneratorConfig = {
|
|
3
|
+
input: string;
|
|
4
|
+
outputDir: string;
|
|
5
|
+
methodNameStrategy?: MethodNameStrategy;
|
|
6
|
+
requesterModuleName?: string;
|
|
7
|
+
specVersion?: string;
|
|
8
|
+
strictVersion?: boolean;
|
|
9
|
+
};
|
|
10
|
+
export type RequesterFunction = <TResponse>(method: string, path: string, options: {
|
|
11
|
+
query?: Record<string, unknown>;
|
|
12
|
+
body?: unknown;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
}) => Promise<TResponse>;
|
|
15
|
+
export type GeneratedMethod = {
|
|
16
|
+
name: string;
|
|
17
|
+
jsDoc: string;
|
|
18
|
+
signature: string;
|
|
19
|
+
implementation: string;
|
|
20
|
+
};
|
|
21
|
+
export type ClientOutput = {
|
|
22
|
+
imports: string[];
|
|
23
|
+
methods: GeneratedMethod[];
|
|
24
|
+
errorTypes: string[];
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type TypeMappingResult = {
|
|
2
|
+
tsType: string;
|
|
3
|
+
imports: string[];
|
|
4
|
+
};
|
|
5
|
+
export type ContractEntry = {
|
|
6
|
+
name: string;
|
|
7
|
+
kind: 'interface' | 'type' | 'enum';
|
|
8
|
+
definition: string;
|
|
9
|
+
jsDoc?: string;
|
|
10
|
+
};
|
|
11
|
+
export type ContractsOutput = {
|
|
12
|
+
entries: ContractEntry[];
|
|
13
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
export type ReferenceObject = {
|
|
2
|
+
$ref: string;
|
|
3
|
+
};
|
|
4
|
+
export type SchemaObject = {
|
|
5
|
+
type?: string | string[];
|
|
6
|
+
format?: string;
|
|
7
|
+
properties?: Record<string, SchemaObject>;
|
|
8
|
+
required?: string[];
|
|
9
|
+
items?: SchemaObject;
|
|
10
|
+
additionalProperties?: boolean | SchemaObject;
|
|
11
|
+
$ref?: string;
|
|
12
|
+
allOf?: SchemaObject[];
|
|
13
|
+
oneOf?: SchemaObject[];
|
|
14
|
+
anyOf?: SchemaObject[];
|
|
15
|
+
enum?: unknown[];
|
|
16
|
+
const?: unknown;
|
|
17
|
+
default?: unknown;
|
|
18
|
+
description?: string;
|
|
19
|
+
nullable?: boolean;
|
|
20
|
+
readOnly?: boolean;
|
|
21
|
+
writeOnly?: boolean;
|
|
22
|
+
externalDocs?: {
|
|
23
|
+
description?: string;
|
|
24
|
+
url: string;
|
|
25
|
+
};
|
|
26
|
+
discriminator?: {
|
|
27
|
+
propertyName: string;
|
|
28
|
+
mapping?: Record<string, string>;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
export type MediaTypeObject = {
|
|
32
|
+
schema?: SchemaObject | ReferenceObject;
|
|
33
|
+
examples?: Record<string, unknown>;
|
|
34
|
+
example?: unknown;
|
|
35
|
+
encoding?: Record<string, unknown>;
|
|
36
|
+
};
|
|
37
|
+
export type ParameterObject = {
|
|
38
|
+
name: string;
|
|
39
|
+
in: 'query' | 'path' | 'header' | 'cookie';
|
|
40
|
+
description?: string;
|
|
41
|
+
required?: boolean;
|
|
42
|
+
deprecated?: boolean;
|
|
43
|
+
schema?: SchemaObject | ReferenceObject;
|
|
44
|
+
style?: string;
|
|
45
|
+
explode?: boolean;
|
|
46
|
+
allowEmptyValue?: boolean;
|
|
47
|
+
example?: unknown;
|
|
48
|
+
examples?: Record<string, unknown>;
|
|
49
|
+
};
|
|
50
|
+
export type RequestBodyObject = {
|
|
51
|
+
description?: string;
|
|
52
|
+
content: Record<string, MediaTypeObject>;
|
|
53
|
+
required?: boolean;
|
|
54
|
+
};
|
|
55
|
+
export type ResponseObject = {
|
|
56
|
+
description: string;
|
|
57
|
+
headers?: Record<string, unknown>;
|
|
58
|
+
content?: Record<string, MediaTypeObject>;
|
|
59
|
+
links?: Record<string, unknown>;
|
|
60
|
+
};
|
|
61
|
+
export type ResponsesObject = Record<string, ResponseObject | ReferenceObject>;
|
|
62
|
+
export type OperationObject = {
|
|
63
|
+
tags?: string[];
|
|
64
|
+
summary?: string;
|
|
65
|
+
description?: string;
|
|
66
|
+
operationId?: string;
|
|
67
|
+
parameters?: (ParameterObject | ReferenceObject)[];
|
|
68
|
+
requestBody?: RequestBodyObject | ReferenceObject;
|
|
69
|
+
responses: ResponsesObject;
|
|
70
|
+
deprecated?: boolean;
|
|
71
|
+
security?: unknown[];
|
|
72
|
+
servers?: unknown[];
|
|
73
|
+
};
|
|
74
|
+
export type PathItemObject = {
|
|
75
|
+
$ref?: string;
|
|
76
|
+
summary?: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
get?: OperationObject;
|
|
79
|
+
put?: OperationObject;
|
|
80
|
+
post?: OperationObject;
|
|
81
|
+
delete?: OperationObject;
|
|
82
|
+
options?: OperationObject;
|
|
83
|
+
head?: OperationObject;
|
|
84
|
+
patch?: OperationObject;
|
|
85
|
+
trace?: OperationObject;
|
|
86
|
+
parameters?: (ParameterObject | ReferenceObject)[];
|
|
87
|
+
servers?: unknown[];
|
|
88
|
+
};
|
|
89
|
+
export type PathsObject = Record<string, PathItemObject>;
|
|
90
|
+
export type ServerVariableObject = {
|
|
91
|
+
default: string;
|
|
92
|
+
description?: string;
|
|
93
|
+
enum?: string[];
|
|
94
|
+
};
|
|
95
|
+
export type ServerObject = {
|
|
96
|
+
url: string;
|
|
97
|
+
description?: string;
|
|
98
|
+
variables?: Record<string, ServerVariableObject>;
|
|
99
|
+
};
|
|
100
|
+
export type InfoObject = {
|
|
101
|
+
title: string;
|
|
102
|
+
version: string;
|
|
103
|
+
description?: string;
|
|
104
|
+
termsOfService?: string;
|
|
105
|
+
contact?: {
|
|
106
|
+
name?: string;
|
|
107
|
+
url?: string;
|
|
108
|
+
email?: string;
|
|
109
|
+
};
|
|
110
|
+
license?: {
|
|
111
|
+
name: string;
|
|
112
|
+
url?: string;
|
|
113
|
+
identifier?: string;
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
export type OAuth2FlowBase = {
|
|
117
|
+
refreshUrl?: string;
|
|
118
|
+
scopes: Record<string, string>;
|
|
119
|
+
};
|
|
120
|
+
export type OAuth2FlowImplicit = OAuth2FlowBase & {
|
|
121
|
+
authorizationUrl: string;
|
|
122
|
+
};
|
|
123
|
+
export type OAuth2FlowPassword = OAuth2FlowBase & {
|
|
124
|
+
tokenUrl: string;
|
|
125
|
+
};
|
|
126
|
+
export type OAuth2FlowClientCredentials = OAuth2FlowBase & {
|
|
127
|
+
tokenUrl: string;
|
|
128
|
+
};
|
|
129
|
+
export type OAuth2FlowAuthorizationCode = OAuth2FlowBase & {
|
|
130
|
+
authorizationUrl: string;
|
|
131
|
+
tokenUrl: string;
|
|
132
|
+
};
|
|
133
|
+
export type OAuth2FlowsObject = {
|
|
134
|
+
implicit?: OAuth2FlowImplicit;
|
|
135
|
+
password?: OAuth2FlowPassword;
|
|
136
|
+
clientCredentials?: OAuth2FlowClientCredentials;
|
|
137
|
+
authorizationCode?: OAuth2FlowAuthorizationCode;
|
|
138
|
+
};
|
|
139
|
+
export type SecuritySchemeObject = {
|
|
140
|
+
type: 'apiKey' | 'http' | 'oauth2' | 'openIdConnect';
|
|
141
|
+
description?: string;
|
|
142
|
+
name?: string;
|
|
143
|
+
in?: 'query' | 'header' | 'cookie';
|
|
144
|
+
scheme?: string;
|
|
145
|
+
bearerFormat?: string;
|
|
146
|
+
flows?: OAuth2FlowsObject;
|
|
147
|
+
openIdConnectUrl?: string;
|
|
148
|
+
};
|
|
149
|
+
export type ComponentsObject = {
|
|
150
|
+
schemas?: Record<string, SchemaObject | ReferenceObject>;
|
|
151
|
+
responses?: Record<string, ResponseObject | ReferenceObject>;
|
|
152
|
+
parameters?: Record<string, ParameterObject | ReferenceObject>;
|
|
153
|
+
requestBodies?: Record<string, RequestBodyObject | ReferenceObject>;
|
|
154
|
+
headers?: Record<string, unknown>;
|
|
155
|
+
securitySchemes?: Record<string, SecuritySchemeObject>;
|
|
156
|
+
links?: Record<string, unknown>;
|
|
157
|
+
callbacks?: Record<string, unknown>;
|
|
158
|
+
examples?: Record<string, unknown>;
|
|
159
|
+
};
|
|
160
|
+
export type OpenAPIDocument = {
|
|
161
|
+
openapi: string;
|
|
162
|
+
info: InfoObject;
|
|
163
|
+
servers?: ServerObject[];
|
|
164
|
+
paths?: PathsObject;
|
|
165
|
+
components?: ComponentsObject;
|
|
166
|
+
security?: unknown[];
|
|
167
|
+
tags?: unknown[];
|
|
168
|
+
externalDocs?: {
|
|
169
|
+
description?: string;
|
|
170
|
+
url: string;
|
|
171
|
+
};
|
|
172
|
+
webhooks?: Record<string, PathItemObject>;
|
|
173
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function kebabToPascalCase(str: string): string;
|
|
2
|
+
export declare function camelCase(str: string): string;
|
|
3
|
+
export declare function pascalCase(str: string): string;
|
|
4
|
+
export declare function toPascalCaseSegment(segment: string): string;
|
|
5
|
+
export declare function formatToBrandTypeName(format: string, openApiType: string): string;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export function kebabToPascalCase(str) {
|
|
2
|
+
if (!str)
|
|
3
|
+
return '';
|
|
4
|
+
return str
|
|
5
|
+
.split('-')
|
|
6
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
7
|
+
.join('');
|
|
8
|
+
}
|
|
9
|
+
export function camelCase(str) {
|
|
10
|
+
if (!str)
|
|
11
|
+
return '';
|
|
12
|
+
return str.charAt(0).toLowerCase() + str.slice(1).toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
export function pascalCase(str) {
|
|
15
|
+
if (!str)
|
|
16
|
+
return '';
|
|
17
|
+
return str
|
|
18
|
+
.split(/[\s-_]+/)
|
|
19
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
20
|
+
.join('');
|
|
21
|
+
}
|
|
22
|
+
export function toPascalCaseSegment(segment) {
|
|
23
|
+
if (!segment)
|
|
24
|
+
return '';
|
|
25
|
+
if (/^[A-Z]/.test(segment) && /^[A-Za-z0-9]+$/.test(segment)) {
|
|
26
|
+
return segment;
|
|
27
|
+
}
|
|
28
|
+
if (segment.includes('-')) {
|
|
29
|
+
return kebabToPascalCase(segment);
|
|
30
|
+
}
|
|
31
|
+
return segment.charAt(0).toUpperCase() + segment.slice(1);
|
|
32
|
+
}
|
|
33
|
+
export function formatToBrandTypeName(format, openApiType) {
|
|
34
|
+
const formatName = pascalCase(format);
|
|
35
|
+
let baseType;
|
|
36
|
+
switch (openApiType) {
|
|
37
|
+
case 'string':
|
|
38
|
+
baseType = 'String';
|
|
39
|
+
break;
|
|
40
|
+
case 'number':
|
|
41
|
+
case 'integer':
|
|
42
|
+
baseType = 'Number';
|
|
43
|
+
break;
|
|
44
|
+
case 'boolean':
|
|
45
|
+
baseType = 'Boolean';
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
baseType = openApiType.charAt(0).toUpperCase() + openApiType.slice(1);
|
|
49
|
+
}
|
|
50
|
+
return formatName + baseType;
|
|
51
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AnalyzedOperation } from '../analyzer/path-analyzer.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a string to PascalCase, handling camelCase, kebab-case, snake_case,
|
|
4
|
+
* and colon-separated segments.
|
|
5
|
+
*/
|
|
6
|
+
export declare function toPascalCase(str: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Build a PascalCase type-name prefix from an operation's method + path.
|
|
9
|
+
* get + /api/v1/products → "GetApiV1Products"
|
|
10
|
+
*/
|
|
11
|
+
export declare function getOperationTypePrefix(op: AnalyzedOperation): string;
|
|
12
|
+
/**
|
|
13
|
+
* Determine the success return type for an operation.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getSuccessType(op: AnalyzedOperation): string;
|
|
16
|
+
/**
|
|
17
|
+
* Determine the error type name for an operation.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getErrorType(op: AnalyzedOperation): string;
|
|
20
|
+
/**
|
|
21
|
+
* Generate the auto-generated header comment.
|
|
22
|
+
*/
|
|
23
|
+
export declare function makeHeader(version: string): string;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a string to PascalCase, handling camelCase, kebab-case, snake_case,
|
|
3
|
+
* and colon-separated segments.
|
|
4
|
+
*/
|
|
5
|
+
export function toPascalCase(str) {
|
|
6
|
+
return str
|
|
7
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
8
|
+
.split(/[-_\s:]/)
|
|
9
|
+
.filter(Boolean)
|
|
10
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
11
|
+
.join('');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Build a PascalCase type-name prefix from an operation's method + path.
|
|
15
|
+
* get + /api/v1/products → "GetApiV1Products"
|
|
16
|
+
*/
|
|
17
|
+
export function getOperationTypePrefix(op) {
|
|
18
|
+
const methodPascal = op.method.charAt(0).toUpperCase() + op.method.slice(1).toLowerCase();
|
|
19
|
+
const segments = op.path
|
|
20
|
+
.split('/')
|
|
21
|
+
.filter((s) => s.length > 0)
|
|
22
|
+
.map((s) => {
|
|
23
|
+
const cleaned = s.replace(/[{}]/g, '');
|
|
24
|
+
return toPascalCase(cleaned);
|
|
25
|
+
});
|
|
26
|
+
return methodPascal + segments.join('');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Determine the success return type for an operation.
|
|
30
|
+
*/
|
|
31
|
+
export function getSuccessType(op) {
|
|
32
|
+
const successResponses = op.responses.filter((r) => r.isSuccess);
|
|
33
|
+
if (successResponses.length === 0) {
|
|
34
|
+
return 'unknown';
|
|
35
|
+
}
|
|
36
|
+
const noContent = successResponses.find((r) => r.tsType === 'void');
|
|
37
|
+
const hasOnlyNoContent = noContent && successResponses.every((r) => r.tsType === 'void');
|
|
38
|
+
if (hasOnlyNoContent) {
|
|
39
|
+
return 'void';
|
|
40
|
+
}
|
|
41
|
+
const withSchema = successResponses.filter((r) => r.tsType !== 'void');
|
|
42
|
+
if (withSchema.length === 0) {
|
|
43
|
+
return 'void';
|
|
44
|
+
}
|
|
45
|
+
const prefix = getOperationTypePrefix(op);
|
|
46
|
+
const types = withSchema.map(() => `${prefix}Response`);
|
|
47
|
+
const unique = [...new Set(types)];
|
|
48
|
+
return unique.join(' | ');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Determine the error type name for an operation.
|
|
52
|
+
*/
|
|
53
|
+
export function getErrorType(op) {
|
|
54
|
+
const prefix = getOperationTypePrefix(op);
|
|
55
|
+
const errorResponses = op.responses.filter((r) => !r.isSuccess && r.statusCode !== 'default');
|
|
56
|
+
if (errorResponses.length === 0) {
|
|
57
|
+
return 'never';
|
|
58
|
+
}
|
|
59
|
+
return `${prefix}Errors`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Generate the auto-generated header comment.
|
|
63
|
+
*/
|
|
64
|
+
export function makeHeader(version) {
|
|
65
|
+
return `// Auto-generated by genoc from OpenAPI ${version} spec. DO NOT EDIT.`;
|
|
66
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String utility functions for OpenAPI client generator
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Indent each line of a string by the specified level (2 spaces per level)
|
|
6
|
+
* @param str The string to indent
|
|
7
|
+
* @param level Number of levels to indent (each level = 2 spaces)
|
|
8
|
+
* @returns Indented string, or empty string if input is empty
|
|
9
|
+
*/
|
|
10
|
+
export declare function indent(str: string, level: number): string;
|
|
11
|
+
/**
|
|
12
|
+
* Capitalize the first character of a string
|
|
13
|
+
* @param str The string to capitalize
|
|
14
|
+
* @returns String with first character uppercase, rest unchanged
|
|
15
|
+
*/
|
|
16
|
+
export declare function capitalize(str: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Check if a string is a JavaScript/TypeScript reserved word
|
|
19
|
+
* @param str The string to check
|
|
20
|
+
* @returns True if the string is a reserved word
|
|
21
|
+
*/
|
|
22
|
+
export declare function isReservedWord(str: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Sanitize a string to make it safe for TypeScript identifier usage
|
|
25
|
+
* @param str The string to sanitize
|
|
26
|
+
* @returns Safe TypeScript identifier
|
|
27
|
+
*/
|
|
28
|
+
export declare function sanitizeIdentifier(str: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Quote a key if needed for TypeScript object literals
|
|
31
|
+
* @param key The key to potentially quote
|
|
32
|
+
* @returns Quoted key if needed, original key otherwise
|
|
33
|
+
*/
|
|
34
|
+
export declare function quoteKey(key: string): string;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String utility functions for OpenAPI client generator
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Indent each line of a string by the specified level (2 spaces per level)
|
|
6
|
+
* @param str The string to indent
|
|
7
|
+
* @param level Number of levels to indent (each level = 2 spaces)
|
|
8
|
+
* @returns Indented string, or empty string if input is empty
|
|
9
|
+
*/
|
|
10
|
+
export function indent(str, level) {
|
|
11
|
+
if (!str)
|
|
12
|
+
return '';
|
|
13
|
+
const prefix = ' '.repeat(Math.max(0, level));
|
|
14
|
+
return str
|
|
15
|
+
.split('\n')
|
|
16
|
+
.map((line) => (line ? `${prefix}${line}` : line)) // preserve empty lines without adding extra indentation
|
|
17
|
+
.join('\n');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Capitalize the first character of a string
|
|
21
|
+
* @param str The string to capitalize
|
|
22
|
+
* @returns String with first character uppercase, rest unchanged
|
|
23
|
+
*/
|
|
24
|
+
export function capitalize(str) {
|
|
25
|
+
if (!str)
|
|
26
|
+
return str;
|
|
27
|
+
return str[0].toUpperCase() + str.slice(1);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Check if a string is a JavaScript/TypeScript reserved word
|
|
31
|
+
* @param str The string to check
|
|
32
|
+
* @returns True if the string is a reserved word
|
|
33
|
+
*/
|
|
34
|
+
export function isReservedWord(str) {
|
|
35
|
+
if (!str)
|
|
36
|
+
return false;
|
|
37
|
+
const reservedWords = new Set([
|
|
38
|
+
// Keywords
|
|
39
|
+
'class',
|
|
40
|
+
'return',
|
|
41
|
+
'const',
|
|
42
|
+
'let',
|
|
43
|
+
'var',
|
|
44
|
+
'function',
|
|
45
|
+
'if',
|
|
46
|
+
'else',
|
|
47
|
+
'for',
|
|
48
|
+
'while',
|
|
49
|
+
'do',
|
|
50
|
+
'switch',
|
|
51
|
+
'case',
|
|
52
|
+
'break',
|
|
53
|
+
'continue',
|
|
54
|
+
'try',
|
|
55
|
+
'catch',
|
|
56
|
+
'finally',
|
|
57
|
+
'throw',
|
|
58
|
+
'new',
|
|
59
|
+
'this',
|
|
60
|
+
'super',
|
|
61
|
+
'extends',
|
|
62
|
+
'implements',
|
|
63
|
+
'interface',
|
|
64
|
+
'type',
|
|
65
|
+
'enum',
|
|
66
|
+
'abstract',
|
|
67
|
+
'async',
|
|
68
|
+
'await',
|
|
69
|
+
'yield',
|
|
70
|
+
'import',
|
|
71
|
+
'export',
|
|
72
|
+
'from',
|
|
73
|
+
'default',
|
|
74
|
+
'delete',
|
|
75
|
+
'in',
|
|
76
|
+
'instanceof',
|
|
77
|
+
'typeof',
|
|
78
|
+
'void',
|
|
79
|
+
'with',
|
|
80
|
+
'debugger',
|
|
81
|
+
// Literals
|
|
82
|
+
'null',
|
|
83
|
+
'true',
|
|
84
|
+
'false',
|
|
85
|
+
'undefined',
|
|
86
|
+
'nan',
|
|
87
|
+
'NaN',
|
|
88
|
+
'Infinity',
|
|
89
|
+
// TypeScript specific
|
|
90
|
+
'of',
|
|
91
|
+
'as',
|
|
92
|
+
'keyof',
|
|
93
|
+
'readonly',
|
|
94
|
+
'declare',
|
|
95
|
+
'namespace',
|
|
96
|
+
'module',
|
|
97
|
+
'require',
|
|
98
|
+
'public',
|
|
99
|
+
'private',
|
|
100
|
+
'protected',
|
|
101
|
+
'static',
|
|
102
|
+
'constructor',
|
|
103
|
+
]);
|
|
104
|
+
return reservedWords.has(str.toLowerCase());
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Sanitize a string to make it safe for TypeScript identifier usage
|
|
108
|
+
* @param str The string to sanitize
|
|
109
|
+
* @returns Safe TypeScript identifier
|
|
110
|
+
*/
|
|
111
|
+
export function sanitizeIdentifier(str) {
|
|
112
|
+
if (!str)
|
|
113
|
+
return '_';
|
|
114
|
+
if (/^\d/.test(str)) {
|
|
115
|
+
return `_${str}`;
|
|
116
|
+
}
|
|
117
|
+
if (isReservedWord(str)) {
|
|
118
|
+
return `_${str}`;
|
|
119
|
+
}
|
|
120
|
+
const segments = str
|
|
121
|
+
.replace(/[^a-zA-Z0-9]/g, ' ')
|
|
122
|
+
.split(/\s+/)
|
|
123
|
+
.filter(Boolean);
|
|
124
|
+
const commonReserved = new Set([
|
|
125
|
+
'class',
|
|
126
|
+
'const',
|
|
127
|
+
'function',
|
|
128
|
+
'if',
|
|
129
|
+
'else',
|
|
130
|
+
'for',
|
|
131
|
+
'while',
|
|
132
|
+
'return',
|
|
133
|
+
'var',
|
|
134
|
+
'let',
|
|
135
|
+
]);
|
|
136
|
+
if (segments.length > 0 && commonReserved.has(segments[0].toLowerCase())) {
|
|
137
|
+
const sanitized = str.replace(/[^a-zA-Z0-9]/g, '_');
|
|
138
|
+
const final = sanitized.replace(/_+/g, '_');
|
|
139
|
+
return `_${final}`;
|
|
140
|
+
}
|
|
141
|
+
const ascii = str.replace(/[üöäÜÖÄ]/g, (match) => {
|
|
142
|
+
switch (match) {
|
|
143
|
+
case 'ü':
|
|
144
|
+
return 'u';
|
|
145
|
+
case 'ö':
|
|
146
|
+
return 'o';
|
|
147
|
+
case 'ä':
|
|
148
|
+
return 'a';
|
|
149
|
+
case 'Ü':
|
|
150
|
+
return 'U';
|
|
151
|
+
case 'Ö':
|
|
152
|
+
return 'O';
|
|
153
|
+
case 'Ä':
|
|
154
|
+
return 'A';
|
|
155
|
+
default:
|
|
156
|
+
return match;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
const sanitized = ascii.replace(/[^a-zA-Z0-9$]/g, '_');
|
|
160
|
+
const final = sanitized.replace(/_+/g, '_');
|
|
161
|
+
if (!final || final === '_' || final === '$' || /^[_$]+$/.test(final)) {
|
|
162
|
+
return '_';
|
|
163
|
+
}
|
|
164
|
+
return final;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Quote a key if needed for TypeScript object literals
|
|
168
|
+
* @param key The key to potentially quote
|
|
169
|
+
* @returns Quoted key if needed, original key otherwise
|
|
170
|
+
*/
|
|
171
|
+
export function quoteKey(key) {
|
|
172
|
+
if (!key)
|
|
173
|
+
return '""';
|
|
174
|
+
// Check if the key needs quoting
|
|
175
|
+
const needsQuoting = isReservedWord(key) ||
|
|
176
|
+
/[^a-zA-Z0-9_$]/.test(key) ||
|
|
177
|
+
key.startsWith(' ') ||
|
|
178
|
+
key.endsWith(' ') ||
|
|
179
|
+
key === '' ||
|
|
180
|
+
/^\d/.test(key);
|
|
181
|
+
return needsQuoting ? `"${key}"` : key;
|
|
182
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function isUrl(str: string): boolean;
|
|
2
|
+
export declare function resolveUrl(base: string, ref: string): string;
|
|
3
|
+
export declare function parseJsonPointer(pointer: string): string[];
|
|
4
|
+
export declare function pathSegments(path: string): string[];
|
|
5
|
+
export declare function getPathSegmentsWithParamInfo(path: string): Array<{
|
|
6
|
+
segment: string;
|
|
7
|
+
isParam: boolean;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function isPathParam(segment: string): boolean;
|
|
10
|
+
export declare function extractParamName(segment: string): string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export function isUrl(str) {
|
|
2
|
+
return str.startsWith('http://') || str.startsWith('https://');
|
|
3
|
+
}
|
|
4
|
+
export function resolveUrl(base, ref) {
|
|
5
|
+
if (ref.startsWith('#')) {
|
|
6
|
+
return base + ref;
|
|
7
|
+
}
|
|
8
|
+
if (ref.startsWith('/')) {
|
|
9
|
+
return ref;
|
|
10
|
+
}
|
|
11
|
+
return base + ref;
|
|
12
|
+
}
|
|
13
|
+
export function parseJsonPointer(pointer) {
|
|
14
|
+
if (pointer === '') {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
const segments = pointer.split('/').slice(1);
|
|
18
|
+
return segments.map((segment) => {
|
|
19
|
+
return segment.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function pathSegments(path) {
|
|
23
|
+
return path.split(/[/:]/).filter((segment) => segment.length > 0);
|
|
24
|
+
}
|
|
25
|
+
export function getPathSegmentsWithParamInfo(path) {
|
|
26
|
+
const segments = path.split(/[/:]/).filter((segment) => segment.length > 0);
|
|
27
|
+
return segments.map((segment) => ({
|
|
28
|
+
segment,
|
|
29
|
+
isParam: segment.startsWith('{') && segment.endsWith('}'),
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
export function isPathParam(segment) {
|
|
33
|
+
return segment.startsWith('{') && segment.endsWith('}');
|
|
34
|
+
}
|
|
35
|
+
export function extractParamName(segment) {
|
|
36
|
+
if (!isPathParam(segment)) {
|
|
37
|
+
throw new Error(`Segment is not a path parameter: ${segment}`);
|
|
38
|
+
}
|
|
39
|
+
return segment.slice(1, -1);
|
|
40
|
+
}
|