@pattern-stack/frontend-patterns 0.2.0-alpha.1 → 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 (165) 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 -325
  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/__tests__/naming-utils.test.js +0 -367
  156. package/cli/src/codegen/openapi/client-generator.js +0 -727
  157. package/cli/src/codegen/openapi/confidence-scorer.js +0 -93
  158. package/cli/src/codegen/openapi/hook-config.js +0 -48
  159. package/cli/src/codegen/openapi/hook-generator.js +0 -763
  160. package/cli/src/codegen/openapi/naming-constants.js +0 -98
  161. package/cli/src/codegen/openapi/naming-utils.js +0 -149
  162. package/cli/src/codegen/openapi/parser.js +0 -274
  163. package/cli/src/codegen/openapi/type-generator.js +0 -329
  164. package/dist/codegen/openapi/bulk-types.d.ts +0 -142
  165. package/dist/codegen/openapi/bulk-types.d.ts.map +0 -1
@@ -1,98 +0,0 @@
1
- /**
2
- * Naming Constants
3
- *
4
- * Shared constants for magic strings used across hook and client generators.
5
- * These constants help identify special endpoints that get unique naming treatment.
6
- */
7
-
8
- /**
9
- * Authentication action endpoints
10
- * These endpoints are named directly without CRUD prefixes (e.g., 'login' not 'createLogin')
11
- */
12
- export const AUTH_ACTIONS = [
13
- 'login',
14
- 'logout',
15
- 'register',
16
- 'signup',
17
- 'signin',
18
- 'refresh'
19
- ];
20
-
21
- /**
22
- * Health/status check endpoints
23
- * These are singleton endpoints that return system status
24
- */
25
- export const HEALTH_ENDPOINTS = [
26
- 'health',
27
- 'ready',
28
- 'status',
29
- 'info',
30
- 'version'
31
- ];
32
-
33
- /**
34
- * User profile endpoints
35
- * These endpoints reference the current/authenticated user
36
- */
37
- export const USER_PROFILE_ENDPOINTS = [
38
- 'me',
39
- 'self',
40
- 'profile',
41
- 'current'
42
- ];
43
-
44
- /**
45
- * Singleton resources
46
- * Resources that return a single item, not a collection
47
- * Includes all auth, health, and user profile endpoints plus common singleton patterns
48
- */
49
- export const SINGLETON_RESOURCES = [
50
- 'me',
51
- 'self',
52
- 'current',
53
- 'profile',
54
- 'health',
55
- 'ready',
56
- 'status',
57
- 'info',
58
- 'version',
59
- 'metadata',
60
- 'config',
61
- 'settings',
62
- 'preferences',
63
- 'summary',
64
- 'stats',
65
- 'statistics',
66
- 'dashboard',
67
- 'schema',
68
- 'spec',
69
- 'openapi'
70
- ];
71
-
72
- /**
73
- * Collection action verbs
74
- * Actions that operate on collections (e.g., /activities/search)
75
- */
76
- export const COLLECTION_ACTIONS = [
77
- 'search',
78
- 'export',
79
- 'import',
80
- 'bulk',
81
- 'batch',
82
- 'count',
83
- 'stats',
84
- 'validate'
85
- ];
86
-
87
- /**
88
- * Special actions - combination of auth, health, and user profile endpoints
89
- * These endpoints get special naming treatment and keep their action verb
90
- */
91
- export const SPECIAL_ACTIONS = [
92
- ...AUTH_ACTIONS,
93
- ...HEALTH_ENDPOINTS,
94
- ...USER_PROFILE_ENDPOINTS,
95
- 'check',
96
- 'verify',
97
- 'validate'
98
- ];
@@ -1,149 +0,0 @@
1
- /**
2
- * Shared naming utilities for OpenAPI code generation
3
- * Handles singular/plural conversions with proper edge case handling
4
- */
5
-
6
- /**
7
- * Map of irregular plural forms
8
- */
9
- export const IRREGULAR_PLURALS = {
10
- person: 'people',
11
- child: 'children',
12
- data: 'data', // already plural
13
- media: 'media', // already plural
14
- metadata: 'metadata', // already plural
15
- people: 'people', // already plural
16
- children: 'children', // already plural
17
- };
18
-
19
- /**
20
- * Map of irregular singular forms (reverse lookup)
21
- */
22
- const IRREGULAR_SINGULARS = {
23
- people: 'person',
24
- children: 'child',
25
- data: 'data', // already singular
26
- media: 'media', // already singular
27
- metadata: 'metadata', // already singular
28
- person: 'person', // already singular
29
- child: 'child', // already singular
30
- };
31
-
32
- /**
33
- * Words that naturally end in 's' but are singular
34
- */
35
- const SINGULAR_EXCEPTIONS = [
36
- 'status',
37
- 'class',
38
- 'address',
39
- 'access',
40
- 'success',
41
- 'process',
42
- 'bus',
43
- 'focus',
44
- 'virus',
45
- ];
46
-
47
- /**
48
- * Check if a word is already plural
49
- * @param {string} word - The word to check
50
- * @returns {boolean} - True if the word is plural
51
- */
52
- export function isPlural(word) {
53
- // Check irregular plurals first
54
- if (IRREGULAR_PLURALS[word.toLowerCase()]) {
55
- return IRREGULAR_PLURALS[word.toLowerCase()] === word.toLowerCase();
56
- }
57
-
58
- // Check singular exceptions - these end in 's' but are not plural
59
- if (SINGULAR_EXCEPTIONS.includes(word.toLowerCase())) {
60
- return false;
61
- }
62
-
63
- // Check common plural endings
64
- if (word.endsWith('ies') || word.endsWith('es') || word.endsWith('s')) {
65
- return true;
66
- }
67
-
68
- return false;
69
- }
70
-
71
- /**
72
- * Convert plural word to singular
73
- * @param {string} word - The word to singularize
74
- * @returns {string} - The singular form of the word
75
- */
76
- export function singularize(word) {
77
- // Handle empty or short words
78
- if (!word || word.length <= 1) {
79
- return word;
80
- }
81
-
82
- // Check irregular singulars first
83
- const lowerWord = word.toLowerCase();
84
- if (IRREGULAR_SINGULARS[lowerWord]) {
85
- return IRREGULAR_SINGULARS[lowerWord];
86
- }
87
-
88
- // Already singular (check exceptions)
89
- if (SINGULAR_EXCEPTIONS.includes(lowerWord)) {
90
- return word;
91
- }
92
-
93
- // -ies → -y (activities → activity)
94
- if (word.endsWith('ies')) {
95
- return word.slice(0, -3) + 'y';
96
- }
97
-
98
- // -ses → -s (processes → process, but 'process' is already singular)
99
- // -xes → -x (boxes → box)
100
- // -ches → -ch (watches → watch)
101
- // -shes → -sh (dishes → dish)
102
- if (word.endsWith('ses') || word.endsWith('xes') || word.endsWith('ches') || word.endsWith('shes')) {
103
- return word.slice(0, -2);
104
- }
105
-
106
- // Regular -s ending (cats → cat)
107
- // But avoid words ending in -ss (class, success, etc.)
108
- if (word.endsWith('s') && !word.endsWith('ss') && word.length > 1) {
109
- return word.slice(0, -1);
110
- }
111
-
112
- return word;
113
- }
114
-
115
- /**
116
- * Convert singular word to plural
117
- * @param {string} word - The word to pluralize
118
- * @returns {string} - The plural form of the word
119
- */
120
- export function pluralize(word) {
121
- // Handle empty or short words
122
- if (!word || word.length <= 1) {
123
- return word;
124
- }
125
-
126
- // Check if already plural
127
- if (isPlural(word)) {
128
- return word;
129
- }
130
-
131
- // Check irregular plurals first
132
- const lowerWord = word.toLowerCase();
133
- if (IRREGULAR_PLURALS[lowerWord]) {
134
- return IRREGULAR_PLURALS[lowerWord];
135
- }
136
-
137
- // -y ending (not vowel+y) → -ies (activity → activities)
138
- if (word.endsWith('y') && !['ay', 'ey', 'iy', 'oy', 'uy'].includes(word.slice(-2))) {
139
- return word.slice(0, -1) + 'ies';
140
- }
141
-
142
- // -x, -ch, -sh endings → add 'es' (box → boxes, watch → watches, dish → dishes)
143
- if (word.endsWith('x') || word.endsWith('ch') || word.endsWith('sh')) {
144
- return word + 'es';
145
- }
146
-
147
- // Regular: add 's' (cat → cats, dog → dogs)
148
- return word + 's';
149
- }
@@ -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
- }