Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
27 changes: 14 additions & 13 deletions packages/api/src/codegen/languages/typescript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,20 +230,19 @@ export default class TSGenerator extends CodeGenerator {
let filePath = sourceFile.getFilePath().toString();
filePath = filePath.substring(1);

/**
* It's not Prettier-level of nice but `ts-morph` offers a method of using the TS
* formatter for formatting code which we can use to make our generated SDK not look like
* total garbage.
*
* @see {@link https://ts-morph.com/manipulation/formatting}
*/
sourceFile.formatText();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, TIL! kinda curious about the performance of this vs prettier vs others (but don't think we need to investigate that any time soon)


return {
[filePath]: sourceFile.getFullText(),
};
}),

// Because we're returning the raw source files for TS generation we also need to separately
// emit out our declaration files so we can put those into a separate file in the installed
// SDK directory.
...this.project
.emitToMemory({ emitOnlyDtsFiles: true })
.getFiles()
.map(sourceFile => ({
[path.basename(sourceFile.filePath)]: sourceFile.text,
})),
Comment on lines -238 to -246
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer used and is safe to be removed. It was a remaining artifact of the previous CJS and (attempted) ESM export work where we were generating .d.ts files ourselves.

].reduce((prev, next) => Object.assign(prev, next));
}

Expand Down Expand Up @@ -383,7 +382,7 @@ sdk.server('https://eu.api.example.com/v14');`),
name: 'createSDK',
initializer: writer => {
// `ts-morph` doesn't have any way to cleanly create an IIFE.
writer.writeLine('(() => { return new SDK(); })()');
writer.write('(() => { return new SDK(); })()');
Copy link
Member Author

@erunion erunion Oct 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing this from .writeLine() to .write() fixes a quirk where the ending ; would get placed on the following line because .writeLine() terminates the thing we're writing with a \n.

const createSDK = (() => { return new SDK(); })()
;

and now

const createSDK = (() => { return new SDK(); })();

it's the little things

return writer;
},
},
Expand Down Expand Up @@ -519,7 +518,9 @@ sdk.server('https://eu.api.example.com/v14');`),
moduleSpecifier: `./schemas/${schemaName}`,
});

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

writer.writeLine(`${str} as const`);
writer.write(`${str} as const`);
Copy link
Member Author

@erunion erunion Oct 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the other semicolon fix. These schemas were getting generated like the following:

const schema = {"type": "string"} as const
;

They're now this:

const schema = {"type": "string"} as const;

return writer;
},
},
Expand Down
12 changes: 10 additions & 2 deletions packages/api/test/codegen/languages/typescript/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,22 @@ function assertSDKFixture(file: string, fixture: string) {
await Promise.all(
expectedFiles.map(filename => {
const actual = actualFiles[filename];
const expectedFilePath = path.join(dir, filename);

// We have to wrap in our current package version into the `<<useragent>>` placeholder so
// we don't need to worry about committing package versions into source control or trying
// to mock out our `packageInfo` library, potentially causing sideeffects in other tests.
return fs
.readFile(path.join(dir, filename), 'utf8')
.readFile(expectedFilePath, 'utf8')
.then(expected => expected.replace('<<package version>>', packageInfo.PACKAGE_VERSION))
.then(expected => {
.then(async expected => {
if (actual !== expected && process.env.UPDATE_FIXTURES) {
// eslint-disable-next-line no-console
console.info('[sdk fixture updated]', expectedFilePath);
await fs.writeFile(expectedFilePath, actual.replace(packageInfo.PACKAGE_VERSION, '<<package version>>'));
return;
}

expect(actual).toBe(expected);
});
}),
Expand Down
3 changes: 1 addition & 2 deletions packages/test-utils/sdks/alby/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,6 @@ class SDK {
}
}

const createSDK = (() => { return new SDK(); })()
;
const createSDK = (() => { return new SDK(); })();

export default createSDK;
Original file line number Diff line number Diff line change
@@ -1,5 +1,92 @@
import RuleSource from './RuleSource';

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
;
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;
export default AmqpExternalRulePatch
Original file line number Diff line number Diff line change
@@ -1,5 +1,93 @@
import RuleSource from './RuleSource';

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
;
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;
export default AmqpExternalRulePost
Loading