@workos/oagen-emitters 0.18.2 → 0.18.4

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 (52) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +17 -0
  3. package/dist/index.d.mts.map +1 -1
  4. package/dist/index.mjs +1 -1
  5. package/dist/{plugin-bqfwowQ3.mjs → plugin-Cciic50q.mjs} +457 -101
  6. package/dist/plugin-Cciic50q.mjs.map +1 -0
  7. package/dist/plugin.mjs +1 -1
  8. package/docs/sdk-architecture/rust.md +2 -2
  9. package/package.json +3 -3
  10. package/src/dotnet/fixtures.ts +17 -3
  11. package/src/dotnet/index.ts +2 -1
  12. package/src/dotnet/models.ts +30 -5
  13. package/src/dotnet/naming.ts +10 -0
  14. package/src/dotnet/tests.ts +5 -1
  15. package/src/go/fixtures.ts +4 -2
  16. package/src/go/index.ts +4 -0
  17. package/src/go/models.ts +4 -2
  18. package/src/go/naming.ts +10 -0
  19. package/src/go/resources.ts +19 -6
  20. package/src/kotlin/index.ts +2 -1
  21. package/src/kotlin/models.ts +5 -2
  22. package/src/kotlin/naming.ts +11 -0
  23. package/src/kotlin/tests.ts +5 -1
  24. package/src/node/field-plan.ts +3 -3
  25. package/src/node/index.ts +2 -1
  26. package/src/node/models.ts +40 -1
  27. package/src/node/naming.ts +10 -0
  28. package/src/node/options.ts +45 -1
  29. package/src/node/resources.ts +76 -19
  30. package/src/node/tests.ts +296 -30
  31. package/src/php/index.ts +2 -1
  32. package/src/php/models.ts +11 -5
  33. package/src/php/naming.ts +10 -0
  34. package/src/php/tests.ts +11 -2
  35. package/src/python/fixtures.ts +4 -3
  36. package/src/python/index.ts +2 -1
  37. package/src/python/models.ts +12 -6
  38. package/src/python/naming.ts +10 -0
  39. package/src/python/tests.ts +11 -6
  40. package/src/ruby/index.ts +2 -1
  41. package/src/ruby/models.ts +10 -7
  42. package/src/ruby/naming.ts +10 -0
  43. package/src/ruby/rbi.ts +3 -1
  44. package/src/ruby/tests.ts +4 -1
  45. package/src/rust/index.ts +2 -1
  46. package/src/rust/models.ts +87 -15
  47. package/src/rust/naming.ts +10 -0
  48. package/src/rust/resources.ts +6 -2
  49. package/src/shared/file-header.ts +13 -0
  50. package/test/node/resources.test.ts +31 -2
  51. package/test/rust/models.test.ts +49 -0
  52. package/dist/plugin-bqfwowQ3.mjs.map +0 -1
@@ -921,7 +921,7 @@ describe('inline object-literal baseline parameter types', () => {
921
921
  ],
922
922
  });
923
923
 
924
- const baselineCtx = (service: Service, models: any[]): EmitterContext => ({
924
+ const baselineCtx = (service: Service, models: any[], paramType: string = literalType): EmitterContext => ({
925
925
  ...ctx,
926
926
  spec: { ...emptySpec, services: [service], models },
927
927
  emitterOptions: { ownedServices: ['AdminPortal'] },
@@ -933,7 +933,7 @@ describe('inline object-literal baseline parameter types', () => {
933
933
  generateLink: [
934
934
  {
935
935
  name: 'generateLink',
936
- params: [{ name: 'options', type: literalType, passingStyle: 'options_object' }],
936
+ params: [{ name: 'options', type: paramType, passingStyle: 'options_object' }],
937
937
  returnType: 'Promise<{ link: string }>',
938
938
  async: true,
939
939
  },
@@ -1007,6 +1007,35 @@ describe('inline object-literal baseline parameter types', () => {
1007
1007
  expect(content).toContain(`async generateLink(options: ${literalType})`);
1008
1008
  expect(content).not.toContain('import type { {');
1009
1009
  });
1010
+
1011
+ it('keeps a `{ ... } & X` compound intersection inline even with a named request model', () => {
1012
+ // The adoption guard targets a PURE object literal. A baseline param that
1013
+ // LEADS with a literal but is actually a compound intersection
1014
+ // (`{ ... } & WithMetadata`) carries the hand-authored `& X` portion, which
1015
+ // a named-interface swap would silently drop. It must be preserved verbatim
1016
+ // even though the operation has a single named request-body model.
1017
+ const compoundType = `${literalType} & WithMetadata`;
1018
+ const service = adminPortalService({ kind: 'model', name: 'GenerateLinkBody' });
1019
+ const models = [
1020
+ {
1021
+ name: 'GenerateLinkBody',
1022
+ fields: [
1023
+ { name: 'intent', type: { kind: 'primitive', type: 'string' }, required: true },
1024
+ { name: 'organization', type: { kind: 'primitive', type: 'string' }, required: true },
1025
+ ],
1026
+ },
1027
+ { name: 'PortalLink', fields: [{ name: 'link', type: { kind: 'primitive', type: 'string' }, required: true }] },
1028
+ ];
1029
+
1030
+ const result = generateResources([service], baselineCtx(service, models, compoundType));
1031
+ const content = result.find((f) => f.path === 'src/admin-portal/admin-portal.ts')!.content;
1032
+
1033
+ // The compound type (including the `& WithMetadata` tail) survives intact;
1034
+ // it is NOT replaced by the named `GenerateLinkBody` interface.
1035
+ expect(content).toContain(`async generateLink(options: ${compoundType})`);
1036
+ expect(content).not.toContain('async generateLink(options: GenerateLinkBody)');
1037
+ expect(content).not.toContain('import type { {');
1038
+ });
1010
1039
  });
1011
1040
 
1012
1041
  describe('@oagen-ignore region method filtering', () => {
@@ -119,6 +119,55 @@ describe('rust/models', () => {
119
119
  expect(unions.content).toContain('pub enum EventPayloadOneOf {');
120
120
  });
121
121
 
122
+ it('relaxes the discriminator field on internally-tagged union variants', () => {
123
+ // Mirrors the ApiKey `owner` union: serde's `#[serde(tag = "type")]`
124
+ // consumes `type` as the enum tag and strips it from the variant body, so
125
+ // a *required* `type` field on the variant struct can never be satisfied
126
+ // ("missing field `type`"). The emitter must mark it default+skip_serializing.
127
+ const owner = (name: string, extra: Model['fields'] = []): Model => ({
128
+ name,
129
+ fields: [
130
+ { name: 'type', type: { kind: 'primitive', type: 'string' }, required: true },
131
+ { name: 'id', type: { kind: 'primitive', type: 'string' }, required: true },
132
+ ...extra,
133
+ ],
134
+ });
135
+ const models: Model[] = [
136
+ {
137
+ name: 'ApiKey',
138
+ fields: [
139
+ {
140
+ name: 'owner',
141
+ type: {
142
+ kind: 'union',
143
+ variants: [
144
+ { kind: 'model', name: 'ApiKeyOwner' },
145
+ { kind: 'model', name: 'UserApiKeyOwner' },
146
+ ],
147
+ discriminator: {
148
+ property: 'type',
149
+ mapping: { organization: 'ApiKeyOwner', user: 'UserApiKeyOwner' },
150
+ },
151
+ },
152
+ required: true,
153
+ },
154
+ ],
155
+ },
156
+ owner('ApiKeyOwner'),
157
+ owner('UserApiKeyOwner', [
158
+ { name: 'organization_id', type: { kind: 'primitive', type: 'string' }, required: true },
159
+ ]),
160
+ ];
161
+ const files = generateModels(models, ctx, new UnionRegistry());
162
+ for (const mod of ['api_key_owner', 'user_api_key_owner']) {
163
+ const f = files.find((x) => x.path === `src/models/${mod}.rs`)!;
164
+ expect(f.content).toContain('#[serde(rename = "type", default, skip_serializing)]');
165
+ expect(f.content).toContain('pub type_: String,');
166
+ // The non-discriminator field is untouched.
167
+ expect(f.content).toContain('pub id: String,');
168
+ }
169
+ });
170
+
122
171
  it('documents Field.default as a "Defaults to" doc comment', () => {
123
172
  const models: Model[] = [
124
173
  {