@workos/oagen-emitters 0.2.1 → 0.4.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 (136) hide show
  1. package/.husky/pre-commit +1 -0
  2. package/.release-please-manifest.json +1 -1
  3. package/CHANGELOG.md +15 -0
  4. package/README.md +129 -0
  5. package/dist/index.d.mts +13 -1
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +14549 -3385
  8. package/dist/index.mjs.map +1 -1
  9. package/docs/sdk-architecture/dotnet.md +336 -0
  10. package/docs/sdk-architecture/go.md +338 -0
  11. package/docs/sdk-architecture/php.md +315 -0
  12. package/docs/sdk-architecture/python.md +511 -0
  13. package/oagen.config.ts +328 -2
  14. package/package.json +9 -5
  15. package/scripts/generate-php.js +13 -0
  16. package/scripts/git-push-with-published-oagen.sh +21 -0
  17. package/smoke/sdk-dotnet.ts +45 -12
  18. package/smoke/sdk-go.ts +116 -42
  19. package/smoke/sdk-php.ts +28 -26
  20. package/smoke/sdk-python.ts +5 -2
  21. package/src/dotnet/client.ts +89 -0
  22. package/src/dotnet/enums.ts +323 -0
  23. package/src/dotnet/fixtures.ts +236 -0
  24. package/src/dotnet/index.ts +246 -0
  25. package/src/dotnet/manifest.ts +36 -0
  26. package/src/dotnet/models.ts +344 -0
  27. package/src/dotnet/naming.ts +330 -0
  28. package/src/dotnet/resources.ts +622 -0
  29. package/src/dotnet/tests.ts +693 -0
  30. package/src/dotnet/type-map.ts +201 -0
  31. package/src/dotnet/wrappers.ts +186 -0
  32. package/src/go/client.ts +141 -0
  33. package/src/go/enums.ts +196 -0
  34. package/src/go/fixtures.ts +212 -0
  35. package/src/go/index.ts +84 -0
  36. package/src/go/manifest.ts +36 -0
  37. package/src/go/models.ts +254 -0
  38. package/src/go/naming.ts +179 -0
  39. package/src/go/resources.ts +827 -0
  40. package/src/go/tests.ts +751 -0
  41. package/src/go/type-map.ts +82 -0
  42. package/src/go/wrappers.ts +261 -0
  43. package/src/index.ts +4 -0
  44. package/src/kotlin/client.ts +53 -0
  45. package/src/kotlin/enums.ts +162 -0
  46. package/src/kotlin/index.ts +92 -0
  47. package/src/kotlin/manifest.ts +55 -0
  48. package/src/kotlin/models.ts +395 -0
  49. package/src/kotlin/naming.ts +223 -0
  50. package/src/kotlin/overrides.ts +25 -0
  51. package/src/kotlin/resources.ts +667 -0
  52. package/src/kotlin/tests.ts +1019 -0
  53. package/src/kotlin/type-map.ts +123 -0
  54. package/src/kotlin/wrappers.ts +168 -0
  55. package/src/node/client.ts +128 -115
  56. package/src/node/enums.ts +9 -0
  57. package/src/node/errors.ts +37 -232
  58. package/src/node/field-plan.ts +726 -0
  59. package/src/node/fixtures.ts +9 -1
  60. package/src/node/index.ts +3 -9
  61. package/src/node/models.ts +178 -21
  62. package/src/node/naming.ts +49 -111
  63. package/src/node/resources.ts +527 -397
  64. package/src/node/sdk-errors.ts +41 -0
  65. package/src/node/tests.ts +69 -19
  66. package/src/node/type-map.ts +4 -2
  67. package/src/node/utils.ts +13 -71
  68. package/src/node/wrappers.ts +151 -0
  69. package/src/php/client.ts +179 -0
  70. package/src/php/enums.ts +67 -0
  71. package/src/php/errors.ts +9 -0
  72. package/src/php/fixtures.ts +181 -0
  73. package/src/php/index.ts +96 -0
  74. package/src/php/manifest.ts +36 -0
  75. package/src/php/models.ts +310 -0
  76. package/src/php/naming.ts +279 -0
  77. package/src/php/resources.ts +636 -0
  78. package/src/php/tests.ts +609 -0
  79. package/src/php/type-map.ts +90 -0
  80. package/src/php/utils.ts +18 -0
  81. package/src/php/wrappers.ts +152 -0
  82. package/src/python/client.ts +345 -0
  83. package/src/python/enums.ts +313 -0
  84. package/src/python/fixtures.ts +196 -0
  85. package/src/python/index.ts +95 -0
  86. package/src/python/manifest.ts +38 -0
  87. package/src/python/models.ts +688 -0
  88. package/src/python/naming.ts +189 -0
  89. package/src/python/resources.ts +1322 -0
  90. package/src/python/tests.ts +1335 -0
  91. package/src/python/type-map.ts +93 -0
  92. package/src/python/wrappers.ts +191 -0
  93. package/src/shared/model-utils.ts +472 -0
  94. package/src/shared/naming-utils.ts +154 -0
  95. package/src/shared/non-spec-services.ts +54 -0
  96. package/src/shared/resolved-ops.ts +109 -0
  97. package/src/shared/wrapper-utils.ts +70 -0
  98. package/test/dotnet/client.test.ts +121 -0
  99. package/test/dotnet/enums.test.ts +193 -0
  100. package/test/dotnet/errors.test.ts +9 -0
  101. package/test/dotnet/manifest.test.ts +82 -0
  102. package/test/dotnet/models.test.ts +260 -0
  103. package/test/dotnet/resources.test.ts +255 -0
  104. package/test/dotnet/tests.test.ts +202 -0
  105. package/test/go/client.test.ts +92 -0
  106. package/test/go/enums.test.ts +132 -0
  107. package/test/go/errors.test.ts +9 -0
  108. package/test/go/models.test.ts +265 -0
  109. package/test/go/resources.test.ts +408 -0
  110. package/test/go/tests.test.ts +143 -0
  111. package/test/kotlin/models.test.ts +135 -0
  112. package/test/kotlin/tests.test.ts +176 -0
  113. package/test/node/client.test.ts +92 -12
  114. package/test/node/enums.test.ts +2 -0
  115. package/test/node/errors.test.ts +2 -41
  116. package/test/node/models.test.ts +2 -0
  117. package/test/node/naming.test.ts +23 -0
  118. package/test/node/resources.test.ts +315 -84
  119. package/test/node/serializers.test.ts +3 -1
  120. package/test/node/type-map.test.ts +11 -0
  121. package/test/php/client.test.ts +95 -0
  122. package/test/php/enums.test.ts +173 -0
  123. package/test/php/errors.test.ts +9 -0
  124. package/test/php/models.test.ts +497 -0
  125. package/test/php/resources.test.ts +682 -0
  126. package/test/php/tests.test.ts +185 -0
  127. package/test/python/client.test.ts +200 -0
  128. package/test/python/enums.test.ts +228 -0
  129. package/test/python/errors.test.ts +16 -0
  130. package/test/python/manifest.test.ts +74 -0
  131. package/test/python/models.test.ts +716 -0
  132. package/test/python/resources.test.ts +617 -0
  133. package/test/python/tests.test.ts +202 -0
  134. package/src/node/common.ts +0 -273
  135. package/src/node/config.ts +0 -71
  136. package/src/node/serializers.ts +0 -746
@@ -0,0 +1,189 @@
1
+ import type { Operation, Service, EmitterContext } from '@workos/oagen';
2
+ import { toPascalCase, toSnakeCase } from '@workos/oagen';
3
+ import { buildResolvedLookup, lookupMethodName, getMountTarget } from '../shared/resolved-ops.js';
4
+ import { stripUrnPrefix, applyAcronymFixes } from '../shared/naming-utils.js';
5
+
6
+ /**
7
+ * Python class names that collide with builtins or typing imports.
8
+ * When a model name resolves to one of these, suffix with "Model".
9
+ */
10
+ const PYTHON_RESERVED_CLASS_NAMES = new Set([
11
+ 'List',
12
+ 'Dict',
13
+ 'Set',
14
+ 'Tuple',
15
+ 'Type',
16
+ 'Any',
17
+ 'Optional',
18
+ 'Union',
19
+ 'Literal',
20
+ 'Final',
21
+ 'ClassVar',
22
+ 'Callable',
23
+ ]);
24
+
25
+ /** PascalCase class name with acronym preservation. */
26
+ export function className(name: string): string {
27
+ let result = applyAcronymFixes(toPascalCase(stripUrnPrefix(name)));
28
+ if (PYTHON_RESERVED_CLASS_NAMES.has(result)) {
29
+ result += 'Model';
30
+ }
31
+ return result;
32
+ }
33
+
34
+ /** snake_case file name (without extension). */
35
+ export function fileName(name: string): string {
36
+ return toSnakeCase(stripUrnPrefix(name));
37
+ }
38
+
39
+ /** snake_case method name. */
40
+ export function methodName(name: string): string {
41
+ return toSnakeCase(name);
42
+ }
43
+
44
+ /** snake_case field name. */
45
+ export function fieldName(name: string): string {
46
+ return toSnakeCase(name);
47
+ }
48
+
49
+ /**
50
+ * Python builtins that should not be shadowed by parameter names.
51
+ * When a path/query param name collides, suffix with underscore.
52
+ */
53
+ const PYTHON_BUILTIN_NAMES = new Set([
54
+ 'type',
55
+ 'id',
56
+ 'list',
57
+ 'dict',
58
+ 'set',
59
+ 'map',
60
+ 'filter',
61
+ 'input',
62
+ 'object',
63
+ 'format',
64
+ 'hash',
65
+ 'range',
66
+ 'dir',
67
+ 'max',
68
+ 'min',
69
+ 'next',
70
+ 'open',
71
+ 'print',
72
+ 'len',
73
+ 'str',
74
+ 'int',
75
+ 'float',
76
+ 'bool',
77
+ 'bytes',
78
+ 'tuple',
79
+ 'super',
80
+ ]);
81
+
82
+ /**
83
+ * Safe parameter name for path/query params that avoids shadowing Python builtins.
84
+ * Body field names should continue to use fieldName() to preserve wire-key compatibility.
85
+ */
86
+ export function safeParamName(name: string): string {
87
+ const snake = toSnakeCase(name);
88
+ return PYTHON_BUILTIN_NAMES.has(snake) ? `${snake}_` : snake;
89
+ }
90
+
91
+ /** snake_case module/directory name. */
92
+ export function moduleName(name: string): string {
93
+ return toSnakeCase(name);
94
+ }
95
+
96
+ /** snake_case property name for service accessors on the client. */
97
+ export function servicePropertyName(name: string): string {
98
+ return toSnakeCase(name);
99
+ }
100
+
101
+ /**
102
+ * Resolve the effective service name, using the overlay-resolved class name
103
+ * when available.
104
+ */
105
+ export function resolveServiceName(service: Service, ctx: EmitterContext): string {
106
+ return resolveClassName(service, ctx);
107
+ }
108
+
109
+ /**
110
+ * Build a map from IR service name to resolved service name.
111
+ */
112
+ export function buildServiceNameMap(services: Service[], ctx: EmitterContext): Map<string, string> {
113
+ const map = new Map<string, string>();
114
+ for (const service of services) {
115
+ map.set(service.name, resolveServiceName(service, ctx));
116
+ }
117
+ return map;
118
+ }
119
+
120
+ /**
121
+ * Resolve the output directory for a service.
122
+ */
123
+ export function resolveServiceDir(resolvedServiceName: string): string {
124
+ return moduleName(resolvedServiceName);
125
+ }
126
+
127
+ /** Resolve the SDK method name for an operation, using resolved operations first. */
128
+ export function resolveMethodName(op: Operation, _service: Service, ctx: EmitterContext): string {
129
+ const lookup = buildResolvedLookup(ctx);
130
+ const resolved = lookupMethodName(op, lookup);
131
+ if (resolved) return resolved;
132
+ // Fallback to overlay, then spec-derived
133
+ const httpKey = `${op.httpMethod.toUpperCase()} ${op.path}`;
134
+ const existing = ctx.overlayLookup?.methodByOperation?.get(httpKey);
135
+ if (existing) return toSnakeCase(existing.methodName);
136
+ return toSnakeCase(op.name);
137
+ }
138
+
139
+ /** Resolve the SDK class name for a service, using resolved operations' mountOn. */
140
+ export function resolveClassName(service: Service, ctx: EmitterContext): string {
141
+ // Use resolved ops mountOn as canonical class name (flat pattern like PHP)
142
+ for (const r of ctx.resolvedOperations ?? []) {
143
+ if (r.service.name === service.name) return r.mountOn;
144
+ }
145
+ // Fallback to overlay, then IR name
146
+ if (ctx.overlayLookup?.methodByOperation) {
147
+ for (const op of service.operations) {
148
+ const httpKey = `${op.httpMethod.toUpperCase()} ${op.path}`;
149
+ const existing = ctx.overlayLookup.methodByOperation.get(httpKey);
150
+ if (existing) return existing.className;
151
+ }
152
+ }
153
+ return toPascalCase(service.name);
154
+ }
155
+
156
+ /** Resolve the type name for a model, checking overlay first. */
157
+ export function resolveTypeName(name: string, ctx: EmitterContext): string {
158
+ const existing = ctx.overlayLookup?.interfaceByName?.get(name);
159
+ if (existing) return existing;
160
+ return toPascalCase(stripUrnPrefix(name));
161
+ }
162
+
163
+ /**
164
+ * Build a map from IR service name to mount-target directory name.
165
+ * Every service maps to its mount target's snake_case directory.
166
+ * Replaces the old buildServiceDirMap(grouping) which required namespace grouping.
167
+ */
168
+ export function buildMountDirMap(ctx: EmitterContext): Map<string, string> {
169
+ const map = new Map<string, string>();
170
+ for (const service of ctx.spec.services) {
171
+ const target = getMountTarget(service, ctx);
172
+ map.set(service.name, moduleName(target));
173
+ }
174
+ return map;
175
+ }
176
+
177
+ /** Convert a filesystem directory path (with /) to a Python dotted module path. */
178
+ export function dirToModule(dir: string): string {
179
+ return dir.replace(/\//g, '.');
180
+ }
181
+
182
+ /**
183
+ * Compute the relative import prefix (dots) to reach the namespace root from a given dir depth.
184
+ * With the flat mount-based layout, dirs are always single-level so this returns ".." (2 dots).
185
+ */
186
+ export function relativeImportPrefix(dirName: string): string {
187
+ const depth = dirName.split('/').length;
188
+ return '.'.repeat(depth + 1);
189
+ }