@pattern-stack/frontend-patterns 0.2.0-alpha.0 → 0.2.0-alpha.11

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 (160) hide show
  1. package/dist/atoms/components/core/Badge/Badge.d.ts +1 -1
  2. package/dist/atoms/components/data/DataTable/ColumnFilterDropdown.d.ts +32 -0
  3. package/dist/atoms/components/data/DataTable/ColumnFilterDropdown.d.ts.map +1 -0
  4. package/dist/atoms/components/data/DataTable/ColumnVisibilityToggle.d.ts +32 -0
  5. package/dist/atoms/components/data/DataTable/ColumnVisibilityToggle.d.ts.map +1 -0
  6. package/dist/atoms/components/data/DataTable/DataTable.d.ts +5 -2
  7. package/dist/atoms/components/data/DataTable/DataTable.d.ts.map +1 -1
  8. package/dist/atoms/components/data/DataTable/DataTable.expansion.d.ts +91 -0
  9. package/dist/atoms/components/data/DataTable/DataTable.expansion.d.ts.map +1 -0
  10. package/dist/atoms/components/data/DataTable/DataTable.filters.d.ts +271 -0
  11. package/dist/atoms/components/data/DataTable/DataTable.filters.d.ts.map +1 -0
  12. package/dist/atoms/components/data/DataTable/DataTable.types.d.ts +155 -5
  13. package/dist/atoms/components/data/DataTable/DataTable.types.d.ts.map +1 -1
  14. package/dist/atoms/components/data/DataTable/ExpandButton.d.ts +37 -0
  15. package/dist/atoms/components/data/DataTable/ExpandButton.d.ts.map +1 -0
  16. package/dist/atoms/components/data/DataTable/FilterPill.d.ts +25 -0
  17. package/dist/atoms/components/data/DataTable/FilterPill.d.ts.map +1 -0
  18. package/dist/atoms/components/data/DataTable/QuickFilterBar.d.ts +35 -0
  19. package/dist/atoms/components/data/DataTable/QuickFilterBar.d.ts.map +1 -0
  20. package/dist/atoms/components/data/DataTable/filters/BooleanFilterEditor.d.ts +10 -0
  21. package/dist/atoms/components/data/DataTable/filters/BooleanFilterEditor.d.ts.map +1 -0
  22. package/dist/atoms/components/data/DataTable/filters/DateFilterEditor.d.ts +11 -0
  23. package/dist/atoms/components/data/DataTable/filters/DateFilterEditor.d.ts.map +1 -0
  24. package/dist/atoms/components/data/DataTable/filters/MultiSelectFilterEditor.d.ts +10 -0
  25. package/dist/atoms/components/data/DataTable/filters/MultiSelectFilterEditor.d.ts.map +1 -0
  26. package/dist/atoms/components/data/DataTable/filters/NumberFilterEditor.d.ts +10 -0
  27. package/dist/atoms/components/data/DataTable/filters/NumberFilterEditor.d.ts.map +1 -0
  28. package/dist/atoms/components/data/DataTable/filters/SelectFilterEditor.d.ts +10 -0
  29. package/dist/atoms/components/data/DataTable/filters/SelectFilterEditor.d.ts.map +1 -0
  30. package/dist/atoms/components/data/DataTable/filters/TextFilterEditor.d.ts +10 -0
  31. package/dist/atoms/components/data/DataTable/filters/TextFilterEditor.d.ts.map +1 -0
  32. package/dist/atoms/components/data/DataTable/filters/index.d.ts +14 -0
  33. package/dist/atoms/components/data/DataTable/filters/index.d.ts.map +1 -0
  34. package/dist/atoms/components/data/DataTable/index.d.ts +9 -0
  35. package/dist/atoms/components/data/DataTable/index.d.ts.map +1 -1
  36. package/dist/atoms/components/data/ProgressBar/ProgressBar.d.ts +1 -1
  37. package/dist/atoms/components/data/ProgressBar/ProgressBar.d.ts.map +1 -1
  38. package/dist/atoms/components/data/index.d.ts +3 -2
  39. package/dist/atoms/components/data/index.d.ts.map +1 -1
  40. package/dist/atoms/composed/ConnectionStatus/ConnectionStatus.d.ts +16 -0
  41. package/dist/atoms/composed/ConnectionStatus/ConnectionStatus.d.ts.map +1 -0
  42. package/dist/atoms/composed/ConnectionStatus/index.d.ts +3 -0
  43. package/dist/atoms/composed/ConnectionStatus/index.d.ts.map +1 -0
  44. package/dist/atoms/hooks/index.d.ts +9 -0
  45. package/dist/atoms/hooks/index.d.ts.map +1 -1
  46. package/dist/atoms/hooks/useAdaptiveTable.d.ts +49 -0
  47. package/dist/atoms/hooks/useAdaptiveTable.d.ts.map +1 -0
  48. package/dist/atoms/hooks/useApi.d.ts +1 -1
  49. package/dist/atoms/hooks/useApi.d.ts.map +1 -1
  50. package/dist/atoms/hooks/useColumnVisibility.d.ts +75 -0
  51. package/dist/atoms/hooks/useColumnVisibility.d.ts.map +1 -0
  52. package/dist/atoms/hooks/useEntityData.d.ts +36 -0
  53. package/dist/atoms/hooks/useEntityData.d.ts.map +1 -0
  54. package/dist/atoms/hooks/useEntityDetail.d.ts +43 -0
  55. package/dist/atoms/hooks/useEntityDetail.d.ts.map +1 -0
  56. package/dist/atoms/hooks/useExpandedRows.d.ts +66 -0
  57. package/dist/atoms/hooks/useExpandedRows.d.ts.map +1 -0
  58. package/dist/atoms/hooks/useFieldMetadata.d.ts +18 -0
  59. package/dist/atoms/hooks/useFieldMetadata.d.ts.map +1 -0
  60. package/dist/atoms/hooks/useOnlineStatus.d.ts +16 -0
  61. package/dist/atoms/hooks/useOnlineStatus.d.ts.map +1 -0
  62. package/dist/atoms/hooks/useResponsiveTable.d.ts +123 -0
  63. package/dist/atoms/hooks/useResponsiveTable.d.ts.map +1 -0
  64. package/dist/atoms/hooks/useTableFilters.d.ts +92 -0
  65. package/dist/atoms/hooks/useTableFilters.d.ts.map +1 -0
  66. package/dist/atoms/index.d.ts +1 -0
  67. package/dist/atoms/index.d.ts.map +1 -1
  68. package/dist/atoms/primitives/sheet.d.ts +23 -0
  69. package/dist/atoms/primitives/sheet.d.ts.map +1 -0
  70. package/dist/atoms/primitives/table.d.ts.map +1 -1
  71. package/dist/atoms/services/api/client.d.ts +12 -2
  72. package/dist/atoms/services/api/client.d.ts.map +1 -1
  73. package/dist/atoms/services/auth-service.d.ts +15 -0
  74. package/dist/atoms/services/auth-service.d.ts.map +1 -1
  75. package/dist/atoms/services/index.d.ts +2 -2
  76. package/dist/atoms/services/index.d.ts.map +1 -1
  77. package/dist/atoms/shared/config/table-config.d.ts +79 -0
  78. package/dist/atoms/shared/config/table-config.d.ts.map +1 -0
  79. package/dist/atoms/shared/index.d.ts +1 -0
  80. package/dist/atoms/shared/index.d.ts.map +1 -1
  81. package/dist/atoms/types/auth.d.ts +95 -2
  82. package/dist/atoms/types/auth.d.ts.map +1 -1
  83. package/dist/atoms/types/index.d.ts +1 -0
  84. package/dist/atoms/types/index.d.ts.map +1 -1
  85. package/dist/atoms/types/navigation.d.ts +1 -1
  86. package/dist/atoms/types/navigation.d.ts.map +1 -1
  87. package/dist/atoms/types/ui-config.d.ts +46 -11
  88. package/dist/atoms/types/ui-config.d.ts.map +1 -1
  89. package/dist/atoms/types/ui-metadata.d.ts +103 -0
  90. package/dist/atoms/types/ui-metadata.d.ts.map +1 -0
  91. package/dist/atoms/utils/entity-card-mapping.d.ts +105 -0
  92. package/dist/atoms/utils/entity-card-mapping.d.ts.map +1 -0
  93. package/dist/atoms/utils/field-detection.d.ts +2 -2
  94. package/dist/atoms/utils/field-detection.d.ts.map +1 -1
  95. package/dist/atoms/utils/icon-map.d.ts +48 -0
  96. package/dist/atoms/utils/icon-map.d.ts.map +1 -1
  97. package/dist/atoms/utils/index.d.ts +2 -0
  98. package/dist/atoms/utils/index.d.ts.map +1 -1
  99. package/dist/atoms/utils/ui-mapping.d.ts +9 -3
  100. package/dist/atoms/utils/ui-mapping.d.ts.map +1 -1
  101. package/dist/features/auth/components/ProtectedRoute.d.ts +3 -1
  102. package/dist/features/auth/components/ProtectedRoute.d.ts.map +1 -1
  103. package/dist/features/auth/hooks/useAuth.d.ts.map +1 -1
  104. package/dist/features/auth/providers/NoAuthProvider.d.ts +17 -0
  105. package/dist/features/auth/providers/NoAuthProvider.d.ts.map +1 -0
  106. package/dist/features/auth/providers/index.d.ts +1 -0
  107. package/dist/features/auth/providers/index.d.ts.map +1 -1
  108. package/dist/frontend-patterns.css +1 -4554
  109. package/dist/index.d.ts +12 -4
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.es.js +8793 -18275
  112. package/dist/index.es.js.map +1 -1
  113. package/dist/index.js +8790 -18271
  114. package/dist/index.js.map +1 -1
  115. package/dist/molecules/layout/AppHeader/AppHeader.d.ts.map +1 -1
  116. package/dist/molecules/layout/BulkSelectionBar.d.ts +14 -2
  117. package/dist/molecules/layout/BulkSelectionBar.d.ts.map +1 -1
  118. package/dist/molecules/layout/FieldGrid/FieldGrid.d.ts +61 -0
  119. package/dist/molecules/layout/FieldGrid/FieldGrid.d.ts.map +1 -0
  120. package/dist/molecules/layout/FieldGrid/index.d.ts +2 -0
  121. package/dist/molecules/layout/FieldGrid/index.d.ts.map +1 -0
  122. package/dist/molecules/layout/ListToolbar/ListToolbar.d.ts +37 -0
  123. package/dist/molecules/layout/ListToolbar/ListToolbar.d.ts.map +1 -0
  124. package/dist/molecules/layout/ListToolbar/index.d.ts +2 -0
  125. package/dist/molecules/layout/ListToolbar/index.d.ts.map +1 -0
  126. package/dist/molecules/layout/PageTitle/PageTitle.d.ts +17 -0
  127. package/dist/molecules/layout/PageTitle/PageTitle.d.ts.map +1 -0
  128. package/dist/molecules/layout/PageTitle/index.d.ts +2 -0
  129. package/dist/molecules/layout/PageTitle/index.d.ts.map +1 -0
  130. package/dist/molecules/layout/index.d.ts +3 -0
  131. package/dist/molecules/layout/index.d.ts.map +1 -1
  132. package/dist/molecules/layout/navigation-context.d.ts.map +1 -1
  133. package/dist/sync/EntityStoreProvider.d.ts +35 -0
  134. package/dist/sync/EntityStoreProvider.d.ts.map +1 -0
  135. package/dist/sync/createEntityHooks.d.ts +29 -0
  136. package/dist/sync/createEntityHooks.d.ts.map +1 -0
  137. package/dist/sync/createStore.d.ts +65 -0
  138. package/dist/sync/createStore.d.ts.map +1 -0
  139. package/dist/sync/index.d.ts +6 -0
  140. package/dist/sync/index.d.ts.map +1 -0
  141. package/dist/sync/types.d.ts +383 -0
  142. package/dist/sync/types.d.ts.map +1 -0
  143. package/dist/templates/ListPageTemplate.d.ts +21 -0
  144. package/dist/templates/ListPageTemplate.d.ts.map +1 -0
  145. package/dist/templates/admin/AdminCRUDTemplate.d.ts.map +1 -1
  146. package/dist/templates/factory.d.ts +11 -0
  147. package/dist/templates/factory.d.ts.map +1 -1
  148. package/dist/templates/index.d.ts +1 -0
  149. package/dist/templates/index.d.ts.map +1 -1
  150. package/package.json +11 -7
  151. package/cli/commands/generate-hooks.ts +0 -316
  152. package/cli/commands/init.ts +0 -33
  153. package/cli/commands/scaffold.ts +0 -224
  154. package/cli/index.ts +0 -122
  155. package/cli/src/codegen/openapi/client-generator.js +0 -659
  156. package/cli/src/codegen/openapi/hook-generator.js +0 -725
  157. package/cli/src/codegen/openapi/parser.js +0 -274
  158. package/cli/src/codegen/openapi/type-generator.js +0 -329
  159. package/dist/codegen/openapi/bulk-types.d.ts +0 -142
  160. package/dist/codegen/openapi/bulk-types.d.ts.map +0 -1
@@ -1,274 +0,0 @@
1
- /**
2
- * OpenAPI Parser Implementation
3
- *
4
- * Core parser that reads OpenAPI 3.0 specifications and converts them
5
- * into an intermediate representation for code generation.
6
- *
7
- * Part of FRO-11: OpenAPI Parser Implementation
8
- */
9
- import { promises as fs } from 'fs';
10
- import { resolve } from 'path';
11
- // Main parser class
12
- export class OpenAPIParser {
13
- spec;
14
- refs = new Map();
15
- constructor(spec) {
16
- this.spec = spec;
17
- this.buildRefsMap();
18
- }
19
- /**
20
- * Parse the OpenAPI specification into our intermediate representation
21
- */
22
- parse() {
23
- return {
24
- info: this.parseInfo(),
25
- servers: this.parseServers(),
26
- endpoints: this.parseEndpoints(),
27
- schemas: this.parseSchemas(),
28
- security: this.parseSecurity()
29
- };
30
- }
31
- parseInfo() {
32
- return {
33
- title: this.spec.info.title,
34
- version: this.spec.info.version,
35
- description: this.spec.info.description
36
- };
37
- }
38
- parseServers() {
39
- if (!this.spec.servers)
40
- return [];
41
- return this.spec.servers.map(server => ({
42
- url: server.url,
43
- description: server.description,
44
- variables: server.variables ?
45
- Object.fromEntries(Object.entries(server.variables).map(([key, variable]) => [
46
- key,
47
- variable.default || ''
48
- ])) : undefined
49
- }));
50
- }
51
- parseEndpoints() {
52
- const endpoints = [];
53
- for (const [path, pathItem] of Object.entries(this.spec.paths || {})) {
54
- if (!pathItem)
55
- continue;
56
- const methods = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options'];
57
- for (const method of methods) {
58
- const operation = pathItem[method];
59
- if (!operation)
60
- continue;
61
- endpoints.push({
62
- path,
63
- method,
64
- operationId: operation.operationId,
65
- summary: operation.summary,
66
- description: operation.description,
67
- tags: operation.tags,
68
- parameters: this.parseParameters(operation.parameters),
69
- requestBody: operation.requestBody ? this.parseRequestBody(operation.requestBody) : undefined,
70
- responses: this.parseResponses(operation.responses),
71
- security: operation.security ? this.parseOperationSecurity(operation.security) : undefined
72
- });
73
- }
74
- }
75
- return endpoints;
76
- }
77
- parseParameters(parameters) {
78
- if (!parameters)
79
- return [];
80
- return parameters.map(param => {
81
- const resolved = this.resolveRef(param);
82
- return {
83
- name: resolved.name,
84
- in: resolved.in,
85
- required: resolved.required || false,
86
- schema: this.parseSchema(resolved.schema),
87
- description: resolved.description
88
- };
89
- });
90
- }
91
- parseRequestBody(requestBody) {
92
- const resolved = this.resolveRef(requestBody);
93
- return {
94
- required: resolved.required || false,
95
- description: resolved.description,
96
- content: Object.fromEntries(Object.entries(resolved.content || {}).map(([mediaType, mediaTypeObj]) => [
97
- mediaType,
98
- { schema: this.parseSchema(mediaTypeObj.schema) }
99
- ]))
100
- };
101
- }
102
- parseResponses(responses) {
103
- return Object.entries(responses).map(([statusCode, response]) => {
104
- const resolved = this.resolveRef(response);
105
- return {
106
- statusCode,
107
- description: resolved.description,
108
- content: resolved.content ?
109
- Object.fromEntries(Object.entries(resolved.content).map(([mediaType, mediaTypeObj]) => [
110
- mediaType,
111
- { schema: this.parseSchema(mediaTypeObj.schema) }
112
- ])) : undefined,
113
- headers: resolved.headers ?
114
- Object.fromEntries(Object.entries(resolved.headers).map(([headerName, header]) => [
115
- headerName,
116
- this.parseSchema(this.resolveRef(header).schema)
117
- ])) : undefined
118
- };
119
- });
120
- }
121
- parseSchema(schema) {
122
- if (!schema) {
123
- return { type: 'any' };
124
- }
125
- // Handle $ref
126
- if ('$ref' in schema) {
127
- return {
128
- type: 'any', // Will be resolved later
129
- ref: schema.$ref,
130
- originalRef: schema.$ref
131
- };
132
- }
133
- const resolved = schema;
134
- // Handle array type
135
- if (resolved.type === 'array') {
136
- return {
137
- type: 'array',
138
- items: this.parseSchema(resolved.items),
139
- description: resolved.description,
140
- nullable: resolved.nullable
141
- };
142
- }
143
- // Handle object type
144
- if (resolved.type === 'object' || resolved.properties) {
145
- return {
146
- type: 'object',
147
- properties: resolved.properties ?
148
- Object.fromEntries(Object.entries(resolved.properties).map(([propName, propSchema]) => [
149
- propName,
150
- this.parseSchema(propSchema)
151
- ])) : undefined,
152
- required: resolved.required,
153
- description: resolved.description,
154
- nullable: resolved.nullable
155
- };
156
- }
157
- // Handle primitive types
158
- const type = this.mapOpenAPIType(resolved.type);
159
- return {
160
- type,
161
- format: resolved.format,
162
- enum: resolved.enum,
163
- description: resolved.description,
164
- example: resolved.example,
165
- nullable: resolved.nullable
166
- };
167
- }
168
- parseSchemas() {
169
- if (!this.spec.components?.schemas)
170
- return [];
171
- return Object.entries(this.spec.components.schemas).map(([name, schema]) => ({
172
- ...this.parseSchema(schema),
173
- ref: `#/components/schemas/${name}`
174
- }));
175
- }
176
- parseSecurity() {
177
- if (!this.spec.components?.securitySchemes)
178
- return [];
179
- return Object.entries(this.spec.components.securitySchemes).map(([_name, scheme]) => {
180
- const resolved = this.resolveRef(scheme);
181
- return {
182
- type: resolved.type,
183
- scheme: 'scheme' in resolved ? resolved.scheme : undefined,
184
- bearerFormat: 'bearerFormat' in resolved ? resolved.bearerFormat : undefined,
185
- in: 'in' in resolved ? resolved.in : undefined,
186
- name: 'name' in resolved ? resolved.name : undefined,
187
- flows: 'flows' in resolved ? resolved.flows : undefined,
188
- openIdConnectUrl: 'openIdConnectUrl' in resolved ? resolved.openIdConnectUrl : undefined
189
- };
190
- });
191
- }
192
- parseOperationSecurity(_security) {
193
- // Simplified - would need to match with security schemes
194
- return [];
195
- }
196
- mapOpenAPIType(type) {
197
- switch (type) {
198
- case 'string': return 'string';
199
- case 'number': return 'number';
200
- case 'integer': return 'integer';
201
- case 'boolean': return 'boolean';
202
- case 'array': return 'array';
203
- case 'object': return 'object';
204
- case 'null': return 'null';
205
- default: return 'any';
206
- }
207
- }
208
- buildRefsMap() {
209
- // Build a map of all $ref targets for quick resolution
210
- this.traverseAndMapRefs(this.spec, '');
211
- }
212
- traverseAndMapRefs(obj, currentPath) {
213
- if (typeof obj !== 'object' || obj === null)
214
- return;
215
- for (const [key, value] of Object.entries(obj)) {
216
- const path = currentPath ? `${currentPath}/${key}` : key;
217
- if (key === '$ref' && typeof value === 'string') {
218
- // Don't store the ref itself, we'll resolve it when needed
219
- continue;
220
- }
221
- if (typeof value === 'object') {
222
- // Store objects that could be referenced
223
- if (currentPath.includes('/components/')) {
224
- this.refs.set(`#/${path}`, value);
225
- }
226
- this.traverseAndMapRefs(value, path);
227
- }
228
- }
229
- }
230
- resolveRef(item) {
231
- if (typeof item === 'object' && item !== null && '$ref' in item) {
232
- const ref = item.$ref;
233
- const resolved = this.refs.get(ref);
234
- if (!resolved) {
235
- throw new Error(`Could not resolve reference: ${ref}`);
236
- }
237
- return resolved;
238
- }
239
- return item;
240
- }
241
- }
242
- // Factory function for easy usage
243
- export async function parseOpenAPI(spec) {
244
- const parser = new OpenAPIParser(spec);
245
- return parser.parse();
246
- }
247
- // Utility function to load OpenAPI from URL or file
248
- export async function loadOpenAPISpec(source) {
249
- if (source.startsWith('http://') || source.startsWith('https://')) {
250
- // Load from URL
251
- const response = await fetch(source);
252
- if (!response.ok) {
253
- throw new Error(`Failed to load OpenAPI spec from ${source}: ${response.statusText}`);
254
- }
255
- return response.json();
256
- }
257
- else {
258
- // Try to parse as JSON string first
259
- try {
260
- return JSON.parse(source);
261
- }
262
- catch {
263
- // If JSON parse fails, try to read as file
264
- try {
265
- const absolutePath = resolve(source);
266
- const content = await fs.readFile(absolutePath, 'utf8');
267
- return JSON.parse(content);
268
- }
269
- catch (fileError) {
270
- throw new Error(`Failed to load OpenAPI spec: Not a valid URL, JSON string, or file path. ${fileError}`);
271
- }
272
- }
273
- }
274
- }
@@ -1,329 +0,0 @@
1
- /**
2
- * TypeScript Type Generator
3
- *
4
- * Creates TypeScript interfaces and types from parsed OpenAPI schemas
5
- * with proper naming conventions and structure.
6
- *
7
- * Part of FRO-10: TypeScript Type Generator
8
- */
9
- export class TypeScriptGenerator {
10
- options;
11
- generatedTypes = new Set();
12
- refMap = new Map();
13
- constructor(options = {}) {
14
- this.options = {
15
- prefix: options.prefix || '',
16
- suffix: options.suffix || '',
17
- enumStyle: options.enumStyle || 'union',
18
- nullableStyle: options.nullableStyle || 'undefined',
19
- includeJSDoc: options.includeJSDoc !== false,
20
- includeExamples: options.includeExamples !== false
21
- };
22
- }
23
- generate(parsedAPI) {
24
- // Reset state
25
- this.generatedTypes.clear();
26
- this.refMap.clear();
27
- // Build reference map first
28
- this.buildRefMap(parsedAPI);
29
- return {
30
- schemas: this.generateSchemas(parsedAPI.schemas),
31
- endpoints: this.generateEndpointTypes(parsedAPI.endpoints),
32
- parameters: this.generateParameterTypes(parsedAPI.endpoints),
33
- responses: this.generateResponseTypes(parsedAPI.endpoints),
34
- index: this.generateIndexFile()
35
- };
36
- }
37
- buildRefMap(parsedAPI) {
38
- // Build map of ref -> TypeScript type name
39
- parsedAPI.schemas.forEach(schema => {
40
- if (schema.ref) {
41
- const typeName = this.extractTypeNameFromRef(schema.ref);
42
- this.refMap.set(schema.ref, typeName);
43
- }
44
- });
45
- }
46
- generateSchemas(schemas) {
47
- const types = [];
48
- // Add file header
49
- types.push(this.generateFileHeader('Schema Types'));
50
- for (const schema of schemas) {
51
- if (!schema.ref)
52
- continue;
53
- const typeName = this.refMap.get(schema.ref);
54
- if (!typeName || this.generatedTypes.has(typeName))
55
- continue;
56
- const typeDefinition = this.generateSchemaType(schema, typeName);
57
- types.push(typeDefinition);
58
- this.generatedTypes.add(typeName);
59
- }
60
- return types.join('\n\n');
61
- }
62
- generateSchemaType(schema, typeName) {
63
- const lines = [];
64
- // Add JSDoc comment
65
- if (this.options.includeJSDoc && schema.description) {
66
- lines.push(`/**`);
67
- lines.push(` * ${schema.description}`);
68
- if (this.options.includeExamples && schema.example) {
69
- lines.push(` * @example ${JSON.stringify(schema.example)}`);
70
- }
71
- lines.push(` */`);
72
- }
73
- // Generate the type
74
- const typeContent = this.generateTypeContent(schema);
75
- lines.push(`export interface ${typeName} ${typeContent}`);
76
- return lines.join('\n');
77
- }
78
- generateTypeContent(schema) {
79
- switch (schema.type) {
80
- case 'object':
81
- return this.generateObjectType(schema);
82
- case 'array':
83
- return `${this.generateTypeContent(schema.items)}[]`;
84
- case 'string':
85
- if (schema.enum) {
86
- return this.generateEnumType(schema.enum);
87
- }
88
- return this.addNullable('string', schema.nullable);
89
- case 'number':
90
- case 'integer':
91
- return this.addNullable('number', schema.nullable);
92
- case 'boolean':
93
- return this.addNullable('boolean', schema.nullable);
94
- case 'null':
95
- return 'null';
96
- case 'any':
97
- if (schema.ref) {
98
- const refType = this.refMap.get(schema.ref);
99
- return refType || 'unknown';
100
- }
101
- return 'unknown';
102
- default:
103
- return 'unknown';
104
- }
105
- }
106
- generateObjectType(schema) {
107
- if (!schema.properties) {
108
- return '{ [key: string]: unknown }';
109
- }
110
- const properties = [];
111
- for (const [propName, propSchema] of Object.entries(schema.properties)) {
112
- const isRequired = schema.required?.includes(propName) || false;
113
- const isOptional = !isRequired ? '?' : '';
114
- const propType = this.generateTypeContent(propSchema);
115
- // Add JSDoc for property if available
116
- let propDoc = '';
117
- if (this.options.includeJSDoc && propSchema.description) {
118
- propDoc = ` /** ${propSchema.description} */\n `;
119
- }
120
- properties.push(`${propDoc}${propName}${isOptional}: ${propType}`);
121
- }
122
- return `{\n ${properties.join('\n ')}\n}`;
123
- }
124
- generateEnumType(enumValues) {
125
- if (this.options.enumStyle === 'enum') {
126
- // Generate enum declaration (would need to be handled separately)
127
- return enumValues.map(val => `'${val}'`).join(' | ');
128
- }
129
- else {
130
- return enumValues.map(val => `'${val}'`).join(' | ');
131
- }
132
- }
133
- addNullable(type, nullable) {
134
- if (!nullable)
135
- return type;
136
- switch (this.options.nullableStyle) {
137
- case 'null':
138
- return `${type} | null`;
139
- case 'both':
140
- return `${type} | null | undefined`;
141
- case 'undefined':
142
- default:
143
- return `${type} | undefined`;
144
- }
145
- }
146
- generateEndpointTypes(endpoints) {
147
- const types = [];
148
- types.push(this.generateFileHeader('Endpoint Types'));
149
- // Group endpoints by operation ID or path+method
150
- const endpointTypes = new Set();
151
- for (const endpoint of endpoints) {
152
- const operationName = this.getOperationName(endpoint);
153
- if (endpointTypes.has(operationName))
154
- continue;
155
- endpointTypes.add(operationName);
156
- // Generate request type
157
- const requestType = this.generateRequestType(endpoint, operationName);
158
- if (requestType) {
159
- types.push(requestType);
160
- }
161
- // Generate response type
162
- const responseType = this.generateResponseType(endpoint, operationName);
163
- if (responseType) {
164
- types.push(responseType);
165
- }
166
- }
167
- return types.join('\n\n');
168
- }
169
- generateRequestType(endpoint, operationName) {
170
- const hasParams = endpoint.parameters.length > 0;
171
- const hasBody = endpoint.requestBody !== undefined;
172
- if (!hasParams && !hasBody)
173
- return null;
174
- const lines = [];
175
- if (this.options.includeJSDoc) {
176
- lines.push(`/**`);
177
- lines.push(` * Request type for ${endpoint.method.toUpperCase()} ${endpoint.path}`);
178
- if (endpoint.summary) {
179
- lines.push(` * ${endpoint.summary}`);
180
- }
181
- lines.push(` */`);
182
- }
183
- const properties = [];
184
- // Add parameters
185
- if (hasParams) {
186
- const paramsByType = this.groupParametersByType(endpoint.parameters);
187
- for (const [paramType, params] of Object.entries(paramsByType)) {
188
- if (params.length === 0)
189
- continue;
190
- const paramProps = params.map(param => {
191
- const optional = param.required ? '' : '?';
192
- const type = this.generateTypeContent(param.schema);
193
- return ` ${param.name}${optional}: ${type}`;
194
- });
195
- properties.push(` ${paramType}: {\n${paramProps.join('\n')}\n }`);
196
- }
197
- }
198
- // Add request body
199
- if (hasBody && endpoint.requestBody) {
200
- const bodyType = this.generateRequestBodyType(endpoint.requestBody);
201
- const optional = endpoint.requestBody.required ? '' : '?';
202
- properties.push(` body${optional}: ${bodyType}`);
203
- }
204
- const typeName = `${this.formatTypeName(operationName)}Request`;
205
- lines.push(`export interface ${typeName} {`);
206
- lines.push(properties.join('\n'));
207
- lines.push(`}`);
208
- return lines.join('\n');
209
- }
210
- generateResponseType(endpoint, operationName) {
211
- if (endpoint.responses.length === 0)
212
- return null;
213
- const lines = [];
214
- if (this.options.includeJSDoc) {
215
- lines.push(`/**`);
216
- lines.push(` * Response type for ${endpoint.method.toUpperCase()} ${endpoint.path}`);
217
- if (endpoint.summary) {
218
- lines.push(` * ${endpoint.summary}`);
219
- }
220
- lines.push(` */`);
221
- }
222
- // Generate union type for all possible responses
223
- const responseTypes = [];
224
- for (const response of endpoint.responses) {
225
- if (response.content) {
226
- for (const [mediaType, content] of Object.entries(response.content)) {
227
- if (mediaType.includes('json')) {
228
- const type = this.generateTypeContent(content.schema);
229
- responseTypes.push(`{ status: ${response.statusCode}; data: ${type} }`);
230
- }
231
- }
232
- }
233
- else {
234
- responseTypes.push(`{ status: ${response.statusCode}; data: void }`);
235
- }
236
- }
237
- const typeName = `${this.formatTypeName(operationName)}Response`;
238
- const unionType = responseTypes.length > 1 ? responseTypes.join(' | ') : responseTypes[0] || 'void';
239
- lines.push(`export type ${typeName} = ${unionType}`);
240
- return lines.join('\n');
241
- }
242
- generateRequestBodyType(requestBody) {
243
- // Find JSON content type
244
- const jsonContent = requestBody.content['application/json'] ||
245
- requestBody.content['application/vnd.api+json'] ||
246
- Object.values(requestBody.content)[0];
247
- if (!jsonContent)
248
- return 'unknown';
249
- return this.generateTypeContent(jsonContent.schema);
250
- }
251
- generateParameterTypes(_endpoints) {
252
- const types = [];
253
- types.push(this.generateFileHeader('Parameter Types'));
254
- // This could be expanded to generate specific parameter types
255
- // For now, we'll keep it simple
256
- return types.join('\n\n');
257
- }
258
- generateResponseTypes(_endpoints) {
259
- const types = [];
260
- types.push(this.generateFileHeader('Response Types'));
261
- // Additional response type utilities could go here
262
- return types.join('\n\n');
263
- }
264
- generateIndexFile() {
265
- const lines = [];
266
- lines.push(this.generateFileHeader('Generated API Types'));
267
- lines.push('');
268
- lines.push('// Schema exports');
269
- lines.push('export * from \'./schemas\'');
270
- lines.push('');
271
- lines.push('// Endpoint exports');
272
- lines.push('export * from \'./endpoints\'');
273
- lines.push('');
274
- lines.push('// Parameter exports');
275
- lines.push('export * from \'./parameters\'');
276
- lines.push('');
277
- lines.push('// Response exports');
278
- lines.push('export * from \'./responses\'');
279
- return lines.join('\n');
280
- }
281
- generateFileHeader(title) {
282
- return `/**
283
- * ${title}
284
- *
285
- * Auto-generated from OpenAPI specification
286
- * Do not edit manually - regenerate using the OpenAPI type generator
287
- */`;
288
- }
289
- getOperationName(endpoint) {
290
- if (endpoint.operationId) {
291
- return endpoint.operationId;
292
- }
293
- // Generate from path and method
294
- const pathParts = endpoint.path
295
- .split('/')
296
- .filter(part => part && !part.startsWith('{'))
297
- .map(part => this.capitalize(part));
298
- return `${endpoint.method}${pathParts.join('')}`;
299
- }
300
- formatTypeName(name) {
301
- const formatted = this.capitalize(name);
302
- return `${this.options.prefix}${formatted}${this.options.suffix}`;
303
- }
304
- extractTypeNameFromRef(ref) {
305
- const parts = ref.split('/');
306
- const name = parts[parts.length - 1];
307
- return this.formatTypeName(name);
308
- }
309
- groupParametersByType(parameters) {
310
- const grouped = {
311
- path: [],
312
- query: [],
313
- header: [],
314
- cookie: []
315
- };
316
- for (const param of parameters) {
317
- grouped[param.in].push(param);
318
- }
319
- return grouped;
320
- }
321
- capitalize(str) {
322
- return str.charAt(0).toUpperCase() + str.slice(1);
323
- }
324
- }
325
- // Factory function for easy usage
326
- export function generateTypes(parsedAPI, options) {
327
- const generator = new TypeScriptGenerator(options);
328
- return generator.generate(parsedAPI);
329
- }