Skip to content

Commit 046b029

Browse files
authored
feat(api): codegen'd sdks now look a little bit nicer (#769)
1 parent df9cadc commit 046b029

File tree

513 files changed

+22787
-1037
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

513 files changed

+22787
-1037
lines changed

packages/api/src/codegen/languages/typescript/index.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -230,20 +230,19 @@ export default class TSGenerator extends CodeGenerator {
230230
let filePath = sourceFile.getFilePath().toString();
231231
filePath = filePath.substring(1);
232232

233+
/**
234+
* It's not Prettier-level of nice but `ts-morph` offers a method of using the TS
235+
* formatter for formatting code which we can use to make our generated SDK not look like
236+
* total garbage.
237+
*
238+
* @see {@link https://ts-morph.com/manipulation/formatting}
239+
*/
240+
sourceFile.formatText();
241+
233242
return {
234243
[filePath]: sourceFile.getFullText(),
235244
};
236245
}),
237-
238-
// Because we're returning the raw source files for TS generation we also need to separately
239-
// emit out our declaration files so we can put those into a separate file in the installed
240-
// SDK directory.
241-
...this.project
242-
.emitToMemory({ emitOnlyDtsFiles: true })
243-
.getFiles()
244-
.map(sourceFile => ({
245-
[path.basename(sourceFile.filePath)]: sourceFile.text,
246-
})),
247246
].reduce((prev, next) => Object.assign(prev, next));
248247
}
249248

@@ -383,7 +382,7 @@ sdk.server('https://eu.api.example.com/v14');`),
383382
name: 'createSDK',
384383
initializer: writer => {
385384
// `ts-morph` doesn't have any way to cleanly create an IIFE.
386-
writer.writeLine('(() => { return new SDK(); })()');
385+
writer.write('(() => { return new SDK(); })()');
387386
return writer;
388387
},
389388
},
@@ -519,7 +518,9 @@ sdk.server('https://eu.api.example.com/v14');`),
519518
moduleSpecifier: `./schemas/${schemaName}`,
520519
});
521520

522-
let str = JSON.stringify(schema);
521+
// Though we aren't using Prettier to make these generated SDKs look amazing we should at
522+
// least make the schema files we generate not look like completely unreadable garbage.
523+
let str = JSON.stringify(schema, null, 2);
523524
let referencedSchemas = str.match(REF_PLACEHOLDER_REGEX)?.map(s => s.replace(REF_PLACEHOLDER_REGEX, '$1'));
524525
if (referencedSchemas) {
525526
referencedSchemas.sort();
@@ -549,7 +550,7 @@ sdk.server('https://eu.api.example.com/v14');`),
549550
// need to clean them up.
550551
str = str.replace(REF_PLACEHOLDER_REGEX, '$1');
551552

552-
writer.writeLine(`${str} as const`);
553+
writer.write(`${str} as const`);
553554
return writer;
554555
},
555556
},

packages/api/test/codegen/languages/typescript/index.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,22 @@ function assertSDKFixture(file: string, fixture: string) {
5151
await Promise.all(
5252
expectedFiles.map(filename => {
5353
const actual = actualFiles[filename];
54+
const expectedFilePath = path.join(dir, filename);
5455

5556
// We have to wrap in our current package version into the `<<useragent>>` placeholder so
5657
// we don't need to worry about committing package versions into source control or trying
5758
// to mock out our `packageInfo` library, potentially causing sideeffects in other tests.
5859
return fs
59-
.readFile(path.join(dir, filename), 'utf8')
60+
.readFile(expectedFilePath, 'utf8')
6061
.then(expected => expected.replace('<<package version>>', packageInfo.PACKAGE_VERSION))
61-
.then(expected => {
62+
.then(async expected => {
63+
if (actual !== expected && process.env.UPDATE_FIXTURES) {
64+
// eslint-disable-next-line no-console
65+
console.info('[sdk fixture updated]', expectedFilePath);
66+
await fs.writeFile(expectedFilePath, actual.replace(packageInfo.PACKAGE_VERSION, '<<package version>>'));
67+
return;
68+
}
69+
6270
expect(actual).toBe(expected);
6371
});
6472
}),

packages/test-utils/sdks/alby/src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,6 @@ class SDK {
380380
}
381381
}
382382

383-
const createSDK = (() => { return new SDK(); })()
384-
;
383+
const createSDK = (() => { return new SDK(); })();
385384

386385
export default createSDK;
Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,92 @@
11
import RuleSource from './RuleSource';
22

3-
const AmqpExternalRulePatch = {"additionalProperties":false,"properties":{"requestMode":{"description":"Single request mode sends each event separately to the endpoint specified by the rule. You can read more about single request mode events in the <a href=\"https://ably.com/documentation/general/events#batching\">Ably documentation</a>.","enum":["single"],"type":"string","examples":["single"]},"ruleType":{"description":"The type of rule. In this case AMQP external (using Firehose). See the <a href=\"https://ably.com/documentation/general/firehose\">Ably documentation</a> for further information.","enum":["amqp/external"],"type":"string"},"source":RuleSource,"status":{"description":"The status of the rule. Rules can be enabled or disabled.","enum":["enabled","disabled"],"type":"string","examples":["enabled"]},"target":{"additionalProperties":false,"properties":{"enveloped":{"description":"Messages delivered through Reactor are wrapped in an Ably envelope by default that contains metadata about the message and its payload. The form of the envelope depends on whether it is part of a Webhook/Function or a Queue/Firehose rule. For everything besides Webhooks, you can ensure you only get the raw payload by unchecking \"Enveloped\" when setting up the rule.","type":["boolean","null"]},"format":{"type":"string"},"headers":{"description":"If you have additional information to send, you'll need to include the relevant headers.","items":{"properties":{"name":{"description":"The name of the header.","type":"string"},"value":{"description":"The value of the header.","type":"string"}},"type":"object"},"type":"array"},"mandatoryRoute":{"description":"Reject delivery of the message if the route does not exist, otherwise fail silently.","type":"boolean"},"messageTtl":{"description":"You can optionally override the default TTL on a queue and specify a TTL in minutes for messages to be persisted. It is unusual to change the default TTL, so if this field is left empty, the default TTL for the queue will be used.","type":"integer"},"persistentMessages":{"description":"Marks the message as persistent, instructing the broker to write it to disk if it is in a durable queue.","type":"boolean"},"routingKey":{"description":"The AMQP routing key. See this <a href=\"https://knowledge.ably.com/what-is-the-format-of-the-routingkey-for-an-amqp-or-kinesis-reactor-rule\">Ably knowledge base article</a> for details.","type":"string"},"url":{"type":"string"}},"type":"object"}},"type":"object","title":"amqp_external_rule_patch","x-readme-ref-name":"amqp_external_rule_patch"} as const
4-
;
3+
const AmqpExternalRulePatch = {
4+
"additionalProperties": false,
5+
"properties": {
6+
"requestMode": {
7+
"description": "Single request mode sends each event separately to the endpoint specified by the rule. You can read more about single request mode events in the <a href=\"https://ably.com/documentation/general/events#batching\">Ably documentation</a>.",
8+
"enum": [
9+
"single"
10+
],
11+
"type": "string",
12+
"examples": [
13+
"single"
14+
]
15+
},
16+
"ruleType": {
17+
"description": "The type of rule. In this case AMQP external (using Firehose). See the <a href=\"https://ably.com/documentation/general/firehose\">Ably documentation</a> for further information.",
18+
"enum": [
19+
"amqp/external"
20+
],
21+
"type": "string"
22+
},
23+
"source": RuleSource,
24+
"status": {
25+
"description": "The status of the rule. Rules can be enabled or disabled.",
26+
"enum": [
27+
"enabled",
28+
"disabled"
29+
],
30+
"type": "string",
31+
"examples": [
32+
"enabled"
33+
]
34+
},
35+
"target": {
36+
"additionalProperties": false,
37+
"properties": {
38+
"enveloped": {
39+
"description": "Messages delivered through Reactor are wrapped in an Ably envelope by default that contains metadata about the message and its payload. The form of the envelope depends on whether it is part of a Webhook/Function or a Queue/Firehose rule. For everything besides Webhooks, you can ensure you only get the raw payload by unchecking \"Enveloped\" when setting up the rule.",
40+
"type": [
41+
"boolean",
42+
"null"
43+
]
44+
},
45+
"format": {
46+
"type": "string"
47+
},
48+
"headers": {
49+
"description": "If you have additional information to send, you'll need to include the relevant headers.",
50+
"items": {
51+
"properties": {
52+
"name": {
53+
"description": "The name of the header.",
54+
"type": "string"
55+
},
56+
"value": {
57+
"description": "The value of the header.",
58+
"type": "string"
59+
}
60+
},
61+
"type": "object"
62+
},
63+
"type": "array"
64+
},
65+
"mandatoryRoute": {
66+
"description": "Reject delivery of the message if the route does not exist, otherwise fail silently.",
67+
"type": "boolean"
68+
},
69+
"messageTtl": {
70+
"description": "You can optionally override the default TTL on a queue and specify a TTL in minutes for messages to be persisted. It is unusual to change the default TTL, so if this field is left empty, the default TTL for the queue will be used.",
71+
"type": "integer"
72+
},
73+
"persistentMessages": {
74+
"description": "Marks the message as persistent, instructing the broker to write it to disk if it is in a durable queue.",
75+
"type": "boolean"
76+
},
77+
"routingKey": {
78+
"description": "The AMQP routing key. See this <a href=\"https://knowledge.ably.com/what-is-the-format-of-the-routingkey-for-an-amqp-or-kinesis-reactor-rule\">Ably knowledge base article</a> for details.",
79+
"type": "string"
80+
},
81+
"url": {
82+
"type": "string"
83+
}
84+
},
85+
"type": "object"
86+
}
87+
},
88+
"type": "object",
89+
"title": "amqp_external_rule_patch",
90+
"x-readme-ref-name": "amqp_external_rule_patch"
91+
} as const;
592
export default AmqpExternalRulePatch
Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,93 @@
11
import RuleSource from './RuleSource';
22

3-
const AmqpExternalRulePost = {"additionalProperties":false,"properties":{"requestMode":{"description":"Single request mode sends each event separately to the endpoint specified by the rule. You can read more about single request mode events in the <a href=\"https://ably.com/documentation/general/events#batching\">Ably documentation</a>.","enum":["single"],"type":"string","examples":["single"]},"ruleType":{"description":"The type of rule. In this case AMQP external (using Firehose). See the <a href=\"https://ably.com/documentation/general/firehose\">documentation</a> for further information.","enum":["amqp/external"],"type":"string"},"source":RuleSource,"target":{"additionalProperties":false,"properties":{"enveloped":{"description":"Messages delivered through Reactor are wrapped in an Ably envelope by default that contains metadata about the message and its payload. The form of the envelope depends on whether it is part of a Webhook/Function or a Queue/Firehose rule. For everything besides Webhooks, you can ensure you only get the raw payload by unchecking \"Enveloped\" when setting up the rule.","type":["boolean","null"]},"format":{"type":"string"},"headers":{"description":"If you have additional information to send, you'll need to include the relevant headers.","items":{"properties":{"name":{"description":"The name of the header.","type":"string"},"value":{"description":"The value of the header.","type":"string"}},"type":"object"},"type":"array"},"mandatoryRoute":{"description":"Reject delivery of the message if the route does not exist, otherwise fail silently.","type":"boolean"},"messageTtl":{"description":"You can optionally override the default TTL on a queue and specify a TTL in minutes for messages to be persisted. It is unusual to change the default TTL, so if this field is left empty, the default TTL for the queue will be used.","type":"integer"},"persistentMessages":{"description":"Marks the message as persistent, instructing the broker to write it to disk if it is in a durable queue.","type":"boolean"},"routingKey":{"description":"The AMQP routing key. See this <a href=\"https://knowledge.ably.com/what-is-the-format-of-the-routingkey-for-an-amqp-or-kinesis-reactor-rule\">Ably knowledge base article</a> for details.","type":"string"},"url":{"type":"string"}},"required":["url","routingKey","mandatoryRoute","persistentMessages"],"type":"object"}},"required":["ruleType","requestMode","source","target"],"type":"object","title":"amqp_external_rule_post","x-readme-ref-name":"amqp_external_rule_post"} as const
4-
;
3+
const AmqpExternalRulePost = {
4+
"additionalProperties": false,
5+
"properties": {
6+
"requestMode": {
7+
"description": "Single request mode sends each event separately to the endpoint specified by the rule. You can read more about single request mode events in the <a href=\"https://ably.com/documentation/general/events#batching\">Ably documentation</a>.",
8+
"enum": [
9+
"single"
10+
],
11+
"type": "string",
12+
"examples": [
13+
"single"
14+
]
15+
},
16+
"ruleType": {
17+
"description": "The type of rule. In this case AMQP external (using Firehose). See the <a href=\"https://ably.com/documentation/general/firehose\">documentation</a> for further information.",
18+
"enum": [
19+
"amqp/external"
20+
],
21+
"type": "string"
22+
},
23+
"source": RuleSource,
24+
"target": {
25+
"additionalProperties": false,
26+
"properties": {
27+
"enveloped": {
28+
"description": "Messages delivered through Reactor are wrapped in an Ably envelope by default that contains metadata about the message and its payload. The form of the envelope depends on whether it is part of a Webhook/Function or a Queue/Firehose rule. For everything besides Webhooks, you can ensure you only get the raw payload by unchecking \"Enveloped\" when setting up the rule.",
29+
"type": [
30+
"boolean",
31+
"null"
32+
]
33+
},
34+
"format": {
35+
"type": "string"
36+
},
37+
"headers": {
38+
"description": "If you have additional information to send, you'll need to include the relevant headers.",
39+
"items": {
40+
"properties": {
41+
"name": {
42+
"description": "The name of the header.",
43+
"type": "string"
44+
},
45+
"value": {
46+
"description": "The value of the header.",
47+
"type": "string"
48+
}
49+
},
50+
"type": "object"
51+
},
52+
"type": "array"
53+
},
54+
"mandatoryRoute": {
55+
"description": "Reject delivery of the message if the route does not exist, otherwise fail silently.",
56+
"type": "boolean"
57+
},
58+
"messageTtl": {
59+
"description": "You can optionally override the default TTL on a queue and specify a TTL in minutes for messages to be persisted. It is unusual to change the default TTL, so if this field is left empty, the default TTL for the queue will be used.",
60+
"type": "integer"
61+
},
62+
"persistentMessages": {
63+
"description": "Marks the message as persistent, instructing the broker to write it to disk if it is in a durable queue.",
64+
"type": "boolean"
65+
},
66+
"routingKey": {
67+
"description": "The AMQP routing key. See this <a href=\"https://knowledge.ably.com/what-is-the-format-of-the-routingkey-for-an-amqp-or-kinesis-reactor-rule\">Ably knowledge base article</a> for details.",
68+
"type": "string"
69+
},
70+
"url": {
71+
"type": "string"
72+
}
73+
},
74+
"required": [
75+
"url",
76+
"routingKey",
77+
"mandatoryRoute",
78+
"persistentMessages"
79+
],
80+
"type": "object"
81+
}
82+
},
83+
"required": [
84+
"ruleType",
85+
"requestMode",
86+
"source",
87+
"target"
88+
],
89+
"type": "object",
90+
"title": "amqp_external_rule_post",
91+
"x-readme-ref-name": "amqp_external_rule_post"
92+
} as const;
593
export default AmqpExternalRulePost

0 commit comments

Comments
 (0)