Documentation Style Guide¶
This documentation aims to follow the Google Developer Documentation Style Guide. This style is not strictly enforced, but should be deferred to when options are being debated.
Sample code¶
To ensure a consistent experience for readers, the following style rules should be followed when writing sample code. Many of these rules are enforced automatically by the linter for samples in the documentation directory, but small snippets of code inline in markdown files must be checked manually.
These style rules have been written to optimize the experience for novice developers and those new to JavaScript. The language has many advanced features and alternative syntaxes, but they often sacrifice readability for compactness. The decisions in this style guide will therefore differ from what's traditionally selected by engineering teams.
Use a single SDK import¶
Import the entire SDK into a single variable named sdk instead of using multiple, narrow imports.
// Yes
import * as sdk from "@codahq/packs-sdk";
// No
import {makeFormula} from '@codahq/packs-sdk';
import {makeParameter} from '@codahq/packs-sdk';
Having all usages of the SDK prefixed with sdk.{something} makes it easier to distinguish what's part of the SDK and what's not. It also makes it easier to copy and paste code from other places without having to worry about adding imports.
Use double quotes¶
Use double quotes whenever possible.
// Yes
description: "A Hello World example.",
// No
description: 'A Hello World example.',
description: `A Hello World example.`,
Double quotes are required for JSON and often shown in example responses, and so it makes sense to standardize on them.
Prefer string concatenation¶
Prefer string concatenation over template strings for simple cases.
// Yes
let url = "http://example.com/thing/" + thingId;
// No
let url = `http://example.com/thing/${thingId}`;
String concatenation is often easier to read and understand, and doesn't introduce an additional string delimiter. Template strings can be used if multiple variables are being inserted.
Use let for variable declaration¶
Prefer let over const, even in cases where the value is never re-assigned.
// Yes
let url = "http://example.com";
// No
const url = "http://example.com";
The distinction between let and const isn't always clear to newer coders, and the inflexibility of const can lead to more errors as users are playing around with code they copy and pasted.
Exception: File-level constants
File-level constants such as enums and schemas, should use const.
const MaxItems = 100;
const MySchema = sdk.makeObjectSchema(...);
Avoid the ternary operator¶
Use conditional blocks instead.
// Yes
let foo = "bar";
if (isThing) {
foo = "baz";
}
// No
let foo = isThing ? "bar" : "baz";
The ternary operator isn't widely known among newer coders, and the syntax is very opaque if you haven't see it before.
Avoid the spread operator¶
Prefer a more concrete manipulation of objects, when feasible.
// Yes
let result = response.body;
result.foo = "bar";
return result;
// No
return {
...response.body,
foo: 'bar',
}
The syntax may not be familiar to newer coders, and more explicit assignments can make it clearer what's going on.
Always set the key and value¶
Even when the key and value are the same, always set both explicitly.
// Yes
context.fetcher.fetch({
method: "GET",
url: url,
});
// No
context.fetcher.fetch({
method: "GET",
url,
});
The shorthand notation that allows you to omit the value can be confusing to newer coders, especially when they need to adapt the code to work with different variable names.
Avoid destructuring¶
Prefer to pull values out of objects and arrays more explicitly.
// Yes
let items = response.body.items;
let pageToken = response.body.pageToken;
// No
let {items, pageToken} = response.body;
The destructuring syntax may not be familiar to newer coders, and it can easily be confused with creating an object or array.
Exception: Parameters values
Destructuring can be used to separate out the parameters of a formula, such as in the execute function.
execute: async function([width, height], context) {
// ...
}
Always include async and context in formula execute methods¶
Even when a formula doesn't require them, always declare the execute function as async and add context parameter.
// Yes
execute: async ([param], context) => {
return "Hello World!";
},
// No
execute: ([param]) => {
return "Hello World!";
},
This makes it easier to add in fetcher calls later without needing to understand asynchronous programming. While there is a slight performance impact to making a function async unnecessarily, and unused variables are discouraged, the benefits outweigh the costs for new users.
Don't declare schemas inline¶
Even if a schema is only used in one formula, declare it separately.
// Yes
const MySchema = sdk.makeObjectSchema({ ... });
pack.addFormula({
// ...
schema: MySchema,
});
// No
pack.addFormula({
// ...
schema: sdk.makeObjectSchema({ ... });
});
A formula definition can already be quite long, and adding a schema can make it even harder to parse. Additionally, schemas are often reused in a pack (a formula and a sync table, for instance) so it is a best practice to separate them earlier.
Use UpperCamelCase for schema variables¶
Name schema constants using UpperCamelCase, like you would for a class.
// Yes
const MySchema = sdk.makeObjectSchema({ ... });
// No
const mySchema = sdk.makeObjectSchema({ ... });
Although not technically a class, schemas are similar enough and should be treated similarly.
Use the function keyword for most functions¶
Define functions using the function keyword in most cases.
// Yes
pack.addFormula({
// ...
execute: function([a, b], context) {
// ...
},
});
// No
pack.addFormula({
// ...
execute: ([a, b], context) => {
// ...
},
});
// Also no
pack.addFormula({
// ...
execute([a, b], context) {
// ...
},
});
The function keyword makes it very clear to readers that you are defining a function. The arrow function syntax is not as obvious for newer coders, and the latter syntax is another form of object shorthand notation which is discouraged.
Exception: Function as parameters
Arrow functions are allowed for anonymous functions used as parameters, like those used in Array.filter(), etc.
let completed = items.filter(item => item.isComplete);
Formula key order¶
The order of keys in the formula declaration should be:
pack.addFormula({
name: ...,
description: ...,
parameters: ...,
resultType: ...,
// If required.
schema: ...,
items: ...,
isAction: ...,
// Anything else.
execute: ...,
});
Object schema key order¶
The order of keys in an object schema declaration should be:
const MySchema = sdk.makeObjectSchema({
properties: ...,
displayProperty: ...,
idProperty: ...,
featuredProperties: ...,
// If required.
identity: ...,
// Anything else.
});
80 character max line length¶
Limit lines to 80 characters. Horizontal space is limited in the Packs Editor side panel and in the Documentation, and lines more than 80 characters can lead to scroll or wrapping that makes it harder to read.
Writing¶
The rules below apply to the prose on the guide and reference pages, as opposed to the sample code covered above.
Documenting Docs and Go differences¶
Connectors often behave differently in Docs and Go, sometimes requiring separate notes, instructions, screenshots, etc.
A few conventions keep this consistent:
- Lead with the shared behavior. Start a section with an intro sentence or two covering what's common to both products, then describe only the differences. Pull any information that applies to both out of the product-specific blocks and into that intro.
- Put Go first. Whenever the two are presented together, in content tabs or a bulleted list, order Go ahead of Docs.
- Label with the icon and short name. Refer to the products as
:superhuman-go: Goand:superhuman-docs: Docs, including in tab titles and list items.
Choose the format based on the shape of the difference.
Large differences¶
When each product needs more than a sentence, has its own steps, or has its own screenshots, use content tabs. This is the default for anything substantial. Screenshots that only apply to one product belong inside that product's tab.
=== ":superhuman-go: Go"
For formulas the agent fills in the parameter values automatically.
...
=== ":superhuman-docs: Docs"
In the formula editor parameters are entered as comma-separated values.
...
Small differences¶
When each product's difference fits in a single short sentence, use a bulleted list. Format each item as the icon, the bold short name, a spaced hyphen, and the text.
- **:superhuman-go: Go** - The timezone comes from the user's Superhuman account.
- **:superhuman-docs: Docs** - The timezone comes from the document.
Available in only one product¶
When an entire page or section covers a feature that only works on one product, use the custom docs or go admonition. Place it at the top, and keep the body short.
!!! docs "Docs only"
Cards are only supported in :superhuman-docs: Docs.
When a one-product feature is only a single section sitting among two-product content, prefer content tabs instead, with the unsupported product's tab noting just that it isn't supported.
Partial support in one product¶
When a feature mostly works the same but has a limitation on one product, use the go or docs admonition titled "Limited in Go" or "Limited in Docs". Place it at the bottom of the section, after the shared explanation.
!!! go "Limited in Go"
Row references don't resolve in Go the way they do in Docs.
In the reference documentation¶
When a difference is a plain fact about a field or method, add a brief caveat to its TypeScript doc comment rather than the generated markdown. Keep it to a single sentence and use plain text without icon shortcodes, since it also appears in IDE hovers.