You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .github/CONTRIBUTING.md
+97-40
Original file line number
Diff line number
Diff line change
@@ -1,61 +1,39 @@
1
1
# Thanks for taking the time to contribute to Typewriter!
2
2
3
-
It is highly appreciated that you take the time to help improve Typewriter.
3
+
This doc provides a walkthrough of developing on, and contributing to, Typewriter.
4
4
5
5
Please see our [issue template](ISSUE_TEMPLATE.md) for issues specifically.
6
6
7
7
## Issues, Bugfixes and New Language Support
8
8
9
-
Have an idea for improving Typewriter? Submit an issue first, and we'll be happy to help
9
+
Have an idea for improving Typewriter? [Submit an issue first](https://github.com/segmentio/typewriter/issues/new), and we'll be happy to help
10
10
you scope it out and make sure it is a good fit for Typewriter.
11
11
12
12
## Developing on Typewriter
13
13
14
-
### Conventions
15
-
16
-
We follow the [Angular commit guidelines](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines).
17
-
18
-
### Build and run locally
19
-
20
-
```sh
21
-
$ yarn
22
-
$ yarn build
23
-
24
-
# The build library is now available in ./dist
25
-
26
-
# Regenerate the JS example to verify Typewriter is installed correctly
You can regenerate all [example clients](../examples) by running:
41
-
42
-
```sh
43
-
$ yarn run generate-examples
44
-
```
45
-
46
14
### Adding a New Language Target
47
15
48
-
1) Create a `gen-{your-lang-here}.ts` file in [`src/commands`](../src/commands) (see existing commands for examples to work from).
16
+
> Before working towards adding a new language target, please [open an issue on GitHub](https://github.com/segmentio/typewriter/issues/new) that walks through your proposal for the new language support. See the [issue template](ISSUE_TEMPLATE.md) for details.
17
+
18
+
When you are ready to start on a PR:
49
19
50
-
2) Export the variables `command` (the name of the command), `desc` (its description), `builder` (an object that captures the parameters your command takes -- in the majority of cases you can just re-export `builder`in [`src/lib/index.ts`](../src/lib/index.ts)) and `handler` (see below).
20
+
1) Create a `gen-{your-lang-here}.ts` file in [`src/commands`](../src/commands).
51
21
52
-
3) The `handler` export is the function that accepts the user-specified parameters and an object that includes the Tracking Plan events. (Keep in mind that you need to wrap your handler function with `getTypedTrackHandler()` which will supply these to you.) This is where you can extract type information and other metadata from the events and use it to format a data payload that can be renderer out as files.
22
+
2) Export the following variables to create a new `yargs` command:
23
+
-`command`: the name of the command (`gen-js`, `gen-go`, etc.).
24
+
-`desc`: the description shown in `typewriter --help`.
25
+
-`builder`: an object that captures the parameters your command takes. In the majority of cases, you can just re-export `builder` from [`src/lib/index.ts`](../src/lib/index.ts).
26
+
-`handler`: a function that accepts user-specified `params` and Tracking Plan `events`. This is where you can extract type information and other metadata from the `events` and use it compile your Typewriter client, usually with some kind of JSON Schema library (see `Implementing a Typewriter Client Compiler` below).
4) Make sure to include an example application in the [`examples/`](../examples) directory that shows how to use your client library.
73
+
3) Implement your compiler, following the instruction under `Implementing a Typewriter Client Compiler` below.
74
+
75
+
4) Most importantly, make sure to include an example program in the [`examples/`](../examples) directory that shows how to use your client library. You should use the Tracking Plan from [`examples/local-tracking-plans/tracking-plan.json`](../examples/local-tracking-plans/tracking-plan.json).
76
+
77
+
5) Update the [`tests`](../tests/commands) directory to generate snapshot tests for your new language. Simply add a test file: `commands/gen-{language}/gen-{language}.test.ts` with a snapshot test:
- Also: [The Official JSON Schema Spec](https://json-schema.org/specification.html)
95
+
-[The Meta Schema](https://github.com/json-schema-org/json-schema-spec/blob/draft-07/schema.json)
96
+
97
+
At a high-level, a Typewriter client exposes a series of analytics functions, each of which represents a single [`track`](https://segment.com/docs/spec/track/) event. Together, these events form a Tracking Plan and each event has a corresponding JSON Schema. Each of these functions are typed, to provide **build-time validation**, if the underlying language can support it. All functions should support **run-time validation**, since portions of JSON Schema cannot be represented as types (such as regex on strings, for example). Both types of validation are generated using some kind of JSON Schema library, with the former usually generated with [`QuickType`](https://github.com/quicktype/quicktype), while the latter is always a language-specific JSON Schema library ([`AJV.js`](https://github.com/epoberezkin/ajv), [`gojsonschema`](https://github.com/xeipuuv/gojsonschema), etc.).
98
+
99
+
As an example, TypeScript supports build-time validation through TypeScript declarations ([example](../examples/gen-js/ts/analytics/generated/index.d.ts)) which are compiled using [`QuickType`](https://github.com/quicktype/quicktype). Conversely, JavaScript can only support run-time validation, so we use [`AJV.js`](https://github.com/epoberezkin/ajv) to pre-compile a validation function that executes at run-time ([example](../examples/gen-js/js/analytics/generated/index.js)).
100
+
101
+
> Note: When performing run-time validation, you can either pre-compile the validation functions (like we do with `AJV.js`), or you can inline/output the JSON Schema, and call out to your JSON Schema library (like we will do with `gojsonschema`). The latter requires a peer dependency at development/test time on your language's JSON Schema library.
102
+
103
+
> Note: Run-time validation should always respect the `--runtimeValidation` flag so that users can prevent validation issues from throwing errors in production.
104
+
105
+
> Note: For context, the mobile clients don't (yet) perform runtime validation (they perform build-time validation only). Runtime validation is expected of all new languages.
106
+
107
+
[`QuickType`](https://github.com/quicktype/quicktype) is primarily used for building typed clients for JSON, so it generates code for JSON serialization (which we don't need). Generally you can disable this with a `Types Only` or `Classes Only` flag. You can test out `QuickType` in their [online editor here](https://app.quicktype.io/) by throwing in one of the [example JSON Schemas](../examples/local-tracking-plans/tracking-plan.json).
108
+
109
+
The high-level flow for compiling a Typewriter client is as follows:
110
+
111
+
1. If the language supports types, generate types using `QuickType`. See [`gen-android.ts`](../src/commands/gen-android.ts) or [`gen-js > typescript.ts`](../src/commands/gen-js/typescript.ts) as an example.
112
+
2. Generate a function for every event in the Tracking Plan (with typed parameters from #1, if possible). Make sure to normalize the event names (such as `Cart Viewed`) into function names (such as `cartViewed`). Within each function:
113
+
- Generate code to perform run-time JSON Schema validation. See [`gen-js > library.ts`](../src/commands/gen-js/library.ts) as an example.
114
+
- Issue a call to the underlying analytics instance ([`analytics.js`](https://segment.com/docs/sources/website/analytics.js/), [`analytics-go`](https://segment.com/docs/sources/server/go/), etc.).
115
+
116
+
Since JSON Schema has an extensive spec, we only explicitely support the features that are supported by the Segment Protocols Tracking Plan Editor (and tested in: [`tests/__fixtures__/*`](../tests/__fixtures__/tracking-plan-fixture.json)). We'll be working towards improving support for other JSON Schema features (such as `enums`, `anyOf/oneOf/....`, etc.) in the near future. However, when adding support for a new language, you'll only need to support the features documented in [`tests/__fixtures__/*`](../tests/__fixtures__/tracking-plan-fixture.json), at minimum.
117
+
118
+
### Build and run locally
119
+
120
+
```sh
121
+
# Install dependencies
122
+
$ yarn
123
+
# Build the Typewriter CLI
124
+
$ yarn build
125
+
126
+
# Test your Typewriter installation by regenerating the JS example.
You can regenerate all [example clients](../examples) by running:
141
+
142
+
```sh
143
+
$ yarn run generate-examples
144
+
```
145
+
146
+
### Conventions
147
+
148
+
We follow the [Angular commit guidelines](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines).
92
149
93
150
### Deploying
94
151
95
-
You can deploy a new version to `npm` by running:
152
+
You can deploy a new version to [`npm`](https://www.npmjs.com/package/typewriter) by running:
0 commit comments