GithubHelp home page GithubHelp logo

segmentio / typewriter Goto Github PK

View Code? Open in Web Editor NEW
218.0 8.0 50.0 6.89 MB

Type safety + intellisense for your Segment analytics

Home Page: https://segment.com/docs/protocols/typewriter/

License: MIT License

TypeScript 87.73% JavaScript 0.79% Handlebars 11.44% Batchfile 0.04%
analytics segment typescript mobile web nodejs segment-protocols ios

typewriter's Introduction



Typewriter logo



NPM Version License Known Vulnerabilities


Typewriter GIF Example

  • 💪 Strongly Typed Analytics: Generates strongly-typed Segment analytics clients that provide compile-time errors, along with intellisense for event/property names, types and descriptions.

  • 👮 Analytics Testing: Validate your instrumentation matches your spec before deploying to production, so you can fail your CI builds without a manual analytics QA process.

  • 🌐 Cross-Language Support: Supports native clients for analytics.js, analytics-node, analytics-android and analytics-ios.

  • Segment Protocols: Built-in support to sync your typewriter clients with your centralized Segment Tracking Plans.

Get Started

# Walks you through setting up a `typewriter.yml` and generating your first client.
$ npx typewriter init

For more instructions on setting up your typewriter client, such as adding it to your CI, see our documentation.

Contributing

Migrating from v7

Check the instructions on our documentation

  • You'll need to change your Segment Config API Token for a Public API Token
  • v8 doesn't support Analytics-iOS nor Analytics-Android. We recommend using Analytics-Swift and Analytics-Kotlin instead which are supported. If you need to use these libraries you can run v7 specifying the version with your commands:
$ npx typewriter@7 build

typewriter's People

Contributors

alanjcharles avatar andrii-holovko-khealth avatar bryantbiggs avatar bsneed avatar colinking avatar dependabot[bot] avatar didiergarcia avatar dstaley avatar gurdasnijor avatar harsh-joshi99 avatar jay-a-mcbee avatar jpirazusta avatar mothershipper avatar mshwery avatar oscb avatar rowno avatar seanhealy avatar silesky avatar tobad357 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

typewriter's Issues

Suggestion: Typescript only mode

At @echo-health use Typescript in all of our projects and were wondering whether there would be any interest in adding a 'mode' to Typewriter so that it only outputs types that enforce the tracking schema instead of javascript code. We would be happy to take this on as a contribution

This would be preferable for us for the following reasons:

  • It would not impact our bundle size in production at all
  • It would circumvent any issues around browser support + proxies (like: #119)

I'm intentionally not going to propose any naming or CLI flags here to first be able to talk about the idea in principle.

Should you not want this to be in-scope of this project, would you be ok with a separate community contributed package (e.g. Something like ts-typewriter or the like)?

Feature Request: Opt-out/remove throwing of runtime errors

Our application is written in TypeScript and since we use the typewriter-generated type definitions during development and transpilation, throwing runtime errors is unnecessary and introduces instability into the execution of our application. If an analytics event is mis-typed at runtime, I would prefer it not block execution of other application code. Currently, the only way to safeguard these calls would be to wrap each function call in a try/catch and that feels like a lot of unnecessary code that would be better to build into the library itself. It would be very beneficial to have the throwing of runtime errors be configurable or removed entirely.

Happy to provide more information if needed and thanks for the hard work!

Support for Named Exports

I came across this while implementing Typewriter on an internal project. After doing some manual refactoring a few times I think it'd be great to have this baked in into Typewriter.

Currently typewriter exports wraps all your tracking calls inside a class you can instance to execute and allows you to pass an analytics instance.
i.e.

Current Status

Show

const genOptions = (context = {}) => ({
  context: {
    ...context,
    typewriter: {
      name: "gen-js",
      version: "5.1.1"
    }
  }
});
export default class Analytics {
  constructor(analytics) {
    this.analytics = analytics || { track: () => null };
  }
  someThingToTrack(props, context) {
    this.analytics.track("Tracking a Thing", props, genOptions(context));
  }
  (... Many other methods)
}

We where using only a few of those tracking methods in our specific project, so we where shipping a lot of unused code that we weren't able to treeshake.
While it might not look like a a huge code reduction if we add the --runtimeValidation false flag, but it is if we want to keep those 😢

So after talking with @colinking on slack, he mentioned making this issue could be a good first step into the discussion.

Proposal

Final export (after running typewriter gen-js with some flags i.e --runtimeValidation false --export class) would look like this:

Show

let analytics = (window && window.analytics) || { track: () => null } 

export const setaAnalytics = (newAnalytics) => { analytics = newAnalytics }

const genOptions = (context = {}) => ({
  context: {
    ...context,
    typewriter: {
      name: 'gen-js',
      version: '5.0.1'
    }
  }
})


export const someThingToTrack = (props, context, callback = () => {}) => {
  analytics.track('Tracking a Thing', props, genOptions(context), callback)
}

Explanation

  • Implements a new flag --export with parameters class & named-exports (or functions?)
    • We set class as the default value for it to keep backwards compatibility
  • Makes every method now a named export
  • Enables a module variable to be the instance of analytics.js
    • Adds method to be able to override that variable
  • Adds support for the callback parameter

Final Thoughts

  • Easier tree shake / dead code elimination
  • Yei for smaller bundle sizes ❤️

Unable to compile generated Typescript for analytics-node sdk

Hey all - i'm really enjoying using typewriter, thanks for the work here! We've adopted it in our mobile team and are looking at expanding this into our web codebases.

I've generated my typewriter code (sdk: analytics-node language: typescript) using npx typewriter, which succesfully generates the index.ts and segment.ts files. However, there are a bunch of compilation errors within the index.ts file which are preventing the project from being built. E.g:

Screenshot 2021-01-05 at 15 11 03

Is there something i'm missing here or could this be an issue with types not being generated correctly? 🤔

Apologies if I'm missing something obvious, but I thought others might run into (or have already run into) the same issue so felt it worth reaching out. Thanks for your time!

iOS run-time JSON Schema validation

In our JS clients, we have a peer dependency on ajv, which is used in development builds to apply JSON Schema validation at run-time.

In our iOS clients, we don't yet support this kind of run-time support. This means that we can't catch issues that cannot be represented by the Objective-C/Swift type system, such as regexes.

We'll need to evaluate available JSON Schema libraries and identify the best way to

There may be a better option for doing this dependency, in iOS land, via generating the client as a static library or a framework. However, we'll need to do some more digging there.

[Questions] CI environment & `development` versus `production` builds

Hey. I've really been enjoying the new release of Typewriter v7. I did have 2 questions, however, that I was hoping to get some further clarification on.

  1. How does Typewriter work in a CI environment? I'm using a Token Script to supply the token during client generation. However, I have nothing set up in our CI environment and the client generation surprisingly works. Does the library use an internal token in CI-based environments?

  2. I wasn't able to find any difference in running these two commands: npx typewriter development and npx typewriter production. Out of curiosity, should these commands produce different outputs given a Browser-based/TypeScript setup?

PostInstall Fails on Snyk

When following the docs on Segment Official Docs , I get stuck at the very first command npm install --save-dev typewriter@next. The install fails as it is attempting to run a snyk protect command on post install.

Screen Shot 2019-10-17 at 5 33 56 PM

If I get passed the post install by using the -- ignore-scripts option I then again get the same issue when running npx typewriter@next init.

I tried to look at the code for the installed version, but the installed version does not seem to have a release tag on the repo.

Supporting other segment methods

feature proposal ✍️

Please detail the following items when filing a feature request:

Wanted to request that the generated Analytics object would include typed methods for more than just the "track" event.

Ideally, we'd be able to use this as a typesafe wrapper around the whole segment api.

For instance, an example usage from our codebase (simplified):

   // track is an initialized generated analytics client
    window.analytics.identify({
      'ab-test-variation': Cookies.get('ab-test-variation') || 'no-cookie',
    });
    track.variationViewed({
      'ab-test-variation': Cookies.get('ab-test-variation'),
    });

Ideally instead of "window.analytics" we could always just use a generated client with typesafe args.

In the ideal case, it would probably include a schema for the (in this instance) identify call. But even a loose typescript type like {[key: string]: any} would be nice.

Also, thanks for this library! It's fantastic, it's not that often that there is an immediate "I wish this existed", "oh my gosh it does" event.

API request failed when npx typewriter

Hi, first of all thank you for your help if you read this issue.

  • Issue and steps to reproduce.
    => I'm trying to download my latest tracking plan by using npx typewriter on my local environment. But got this error ⚠ API request failed. Using local copy instead.

  • Versions. (Typewriter, OS, language, etc.)
    => Typewriter 7.1.0
    => OS Mac 10.15.4
    => Typescript 3.7.4

  • Screenshots.

Capture d’écran 2020-05-05 à 13 40 27

  • Expected.
    I was expecting to download the tracking plan without any issue as I already did a few weeks ago.

  • Actual.
    But I'm currently stuck, and I can't figure it out.I tried to generate another token with no more luck. My setup did not change since the first setup. The tracking plan ID is correct. I tried to upgrade the typewriter version from 7.0.1 to 7.1.0. Again, the issue is still there.

Any help on this, will be very appreciated 😁
Thank you

Version bump to 4.7.2 to resolve vulnerabilities

Hi! I wanted to propose that a 4.7.2 release be done to address some of the security issues that are present in 4.7.1. I believe main branch has already resolved most of them, but its just not part of the official release. Not sure what the release lifecycle is like, but if there are any roadblocks, like updating packages, etc. happy to help here!

Version command reports pre-releases as "new"

It appears that typewriter version considers a pre-release as a new version. 7.0.0-48 should be < 7.0.0.

$ yarn typewriter version
yarn run v1.19.0
$ /Users/colinking/dev/src/github.com/segmentio/app/node_modules/.bin/typewriter version
Version: 7.0.0 (new! 7.0.0-48)
✨  Done in 2.27s.

Protocols Event Versioning Support

Tracking Plans support versioning of events through a context.protocols.event_version field, which is an integer (defaulting to 1) that determines which version of an event schema to apply. This is oftentimes used in mobile applications, where you have old versions of your mobile application running that will be sending old versions of events. Ideally, you can apply different schemas to old events vs. new events, and event versioning enables exactly that.

We'd like to automate the process of supplying the event version, by having Typewriter set this field for you. We'll likely want to expand typewriter.yml to act as a package.json / yarn.lock for the versions of your events, storing a mapping of event name to version. We'll also want to update the CLI to offer an interactive CLI method for updating event versions.

This issue tracks progress towards supporting event versioning Typewriter.

Attempted import error: <enum> is not exported

Really enjoying Typewriter. Thanks!

I ran in the following error when attempting to import types from analytics/generated/index.d.ts:

Attempted import error: 'SignupType' is not exported from '../../analytics/generated'.

This isn't likely a bug on Typewriter's part, but I'm struggling to proceed at this point.

Reproduction

Generated .d.ts file: (analytics/generated/index.d.ts)

export interface NewsletterSignup {
  /**
   * The type of form that was used to sign up for email
   */
  signup_type: SignupType
}

/**
 * The type of form that was used to sign up for email
 */
export enum SignupType {
  Callout = 'callout',
  Footer = 'footer'
}

analytics/index.ts

import Analytics from './generated'

declare global {
  interface Window {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    analytics: any
  }
}

export default Analytics

Usage:

import Analytics from '../../analytics'
import { SignupType } from '../../analytics/generated'

fn({ signup_type: SignupType.Footer }) // Attempted import error: 'SignupType' is not exported from '../../analytics/generated'

Any noticeable missteps on my part? Thanks.

Android SDK: required property not enforced if type can be null

I'm using the analytics-android java sdk and Typewriter v7.2.1.

Here's an example of what is usually generated if the json schema specifies that a property is required:

json schema

"properties": {
  "someProperty": {
    "type": "string" 
  }
},
"required": [
  "someProperty"
]

generated builder output

public TestEvent build() {
  if(properties.get("someProperty") == null){
      throw new IllegalArgumentException("TestEvent missing required property: someProperty");
  }
  return new TestEvent(properties);
}

However, if the property type can be null, it doesn't enforce that it's provided:

json schema

"properties": {
  "someProperty": {
    "type": ["string", "null"] 
  }
},
"required": [
  "someProperty"
]

generated builder output

public TestEvent build() {
  return new TestEvent(properties);
}

Is this the expected behavior?

Error running typewriter init

Bug report 🐞

  • Issue and steps to reproduce.

  • Versions. (Typewriter, OS, language, etc.)
    IOS: macOS big sur
    node: 14.15.5
    typewriter 7.4.1

  • Screenshots.
    Screen Shot 2021-03-09 at 3 33 53 PM

  • Expected.
    new typewriter.yml and ./analytics

  • Actual.
    error: TypeError: setRawMode is not a function

  • Minimal reproducible example.
    run npx typewriter init or typewriter init

Android Kotlin Support

Thanks for taking the time to contribute to Typewriter!

It is highly appreciated that you take the time to help improve Typewriter.
We appreciate it if you would take the time to write up a bug report or feature request.

Sadly, if we don't receive enough information, or the issue/feature request doesn't
align well with our roadmap, we might respectfully thank you for your time, and close the issue.

Bug fixes and documentation fixes are welcome.

In the case of a bug report 🐞

Please consider the following items when filing a bug report:

  • Issue and steps to reproduce.
  • Versions. (Typewriter, OS, language, etc.)
  • Screenshots.
  • Expected.
  • Actual.
  • Minimal reproducible example.

In the case of a feature proposal ✍️

Please detail the following items when filing a feature request:

  • Any proposed changes, if relevant.
  • The problem that this feature addresses.

In the case of a language proposal 🗺

Please detail the following items when filing a language proposal:

  • A proposed API (for the CLI and for analytics functions in the new client).
  • Explain what library you would use for run-time JSON Schema validation.
  • Whether the language will support build-time validation.
  • Any language-specific considerations

See the contributing guide for more details.

Respect earns Respect 👏

Please respect our Code of Conduct, in short:

  • Using welcoming and inclusive language.
  • Being respectful of differing viewpoints and experiences.
  • Gracefully accepting constructive criticism.
  • Focusing on what is best for the community.
  • Showing empathy towards other community members.

Adding "development" flag changes typewriter behavior (versus omitting it)

From the docs:

 # To build a development client (the default, if not supplied):
 $ npx typewriter development

However, in practice:

sarink$ npx typewriter development
  ✔ Loaded Tracking Plan
    ↪  Downloading the latest version from Segment...
    ↪  Loaded <Project> (​https://app.segment.com/<org>/tracking-plan
  ✔ Removed generated filesuco31GZTjVCJ​) (0 added, 0 modified, 0 removed)
  ✔ Generated client
    ↪  Building for development
    ↪  <Project> (​https://app.segment.com/<org>/protocols/tracking-plans/rs_1d<key>​)
sarink$ npx typewriter 
  ✔ Loaded Tracking Plan
    ↪  Downloading the latest version from Segment...
    ↪  Loaded <Project> (​https://app.segment.com/<org>/tracking-plan
  ✔ Removed generated filesuco31GZTjVCJ​) (0 added, 20 modified, 0 removed)
  ✔ Generated client
    ↪  Building for development
    ↪  <Project> (​https://app.segment.com/<org>/protocols/tracking-plans/rs_1d<key>​)

Notice the difference, 20 modified vs 0 modified, how is this possible? Are we supposed to use development, or not use it? I'm confused.

React Native support

Hi, I would like to propose typewriter support for @segment/analytics-react-native, it seems that with few small modification to the analytics-node templates, we could add support for it. Would you be open for a PR for this?

Typewriter does not respect TYPEWRITER_TOKEN env var

bug report 🐞

OS: Mac 10.15.3
Typewriter: 7.1.0
javascript

From the "API Token Configuration" docs:

Typewriter looks for an API token in three ways, in the following order:

  1. Looks for an environment variable called TYPEWRITER_TOKEN.
  2. Executes a token script from the typewriter.yml. See Token Script for more information.
  3. Reads the contents of a ~/.typewriter file.
    https://segment.com/docs/protocols/apis-and-extensions/typewriter/#api-token-configuration

When I run npx typewriter while passing TYPEWRITER_TOKEN to the env, the token is not recognized by Typewriter. I have added logging on a local Typewriter build that indicates process.env.TYPEWRITER_TOKEN is properly populated, and Typewriter has access.

Looking through the code, it doesn't look like Typewriter is ever looking for the env var. The listTokens function only checks ~/.typewriter and the token script.

Perhaps this is something that made its way into the docs without ever being implemented?

is it possible to use Typewriter outside of segment?

is it possible to use Typewriter outside of segment?

not having to use a segment token?

possibly building types for a for a analytics library that is similar to Segment, but custom.

something like, MyCustomAnalyticsLib.orderCompleted()

Unable to Integrate Typewriter with CircleCI

Issue

My team and I have been trying to integrate Typewriter to our application by following the provided Typewriter documentation.
Attempts at following the Best Practices and Connecting to CI sections have resulted in an error when CircleCI attempts to run the npx typewriter production command.
We would appreciate any assistance in helping to resolve this problem, or guidance for any additional setup that might be necessary to get this working as expected.

Steps to Reproduce

  1. Edit the application's CircleCI config.yml file to run the npx typewriter production command before the yarn run deploy line, as shown in the documentation here.
  2. Push the changes and allow CircleCI to run through the commands.
  3. Observe the output.

Versions

Typewriter: 7.2.1

Screenshots

Screenshot 2020-10-22 at 16 15 21

Expected

The npx typewriter production command runs without any errors, and the Typewriter client (index.js) is generated at the specified directory.

Actual

CircleCI throws the following error upon running the npx typewriter production command:

Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.

[FEATURE] Type generation only option

It would be pretty useful if we could provide a cli option when running to only generate the types and interfaces for the events in the tracking plan.

We want to use our own tracking wrapper for some extra error handling and other middleware, but still want to ensure our types are in line with the tracking plan. Right now, we import the interfaces only, which solves the problem! But theres a lot of generated code we don't particularly care about.

Add a way to use a custom generator

We have an application in which we instrument all events using API track([method name], [parameters]), e.g.

analytics.track('Service Inquiry Sent', {
  existingUser: true,
});

We would like to generate a library compatible with this API. This requires being able to set a custom generator.

This could be as simple as extending typewriter.yaml to allow a link to a custom generator file compatible with existing typewriter generators.

"npx typewriter init" does not show the wizard

  • typewriter version: 7.4.1
  • node version: 10.19.0
  • npm version: 6.14.4
  • npx version: 6.14.4
  • OS: Ubuntu 20.04

When I run npx typewriter init, I expect that I should see an interactive wizard in the terminal. Instead, it only shows:

  • a progress indicator
  • then npx: installed 157 in 9.95s
  • then Typewriter is a tool for generating strongly-typed Segment analytics libraries
  • then it shows whitespace, and does not exit.

Screenshot from 2021-03-19 16-47-01

Clean up dependencies

What

There are a lot of dependencies that should be peer dependencies or dev dependencies.

Why

Project using this library should not be required to download e.g typescript, prettier, babel, react etc.

Colored text rendered incorrectly on certain terminals

Normally, typewriter init looks like this:

init

However, on a default Ubuntu terminal, it'll render like this:

image

When highlighting text, you'll see that the text is structured correctly, but not visible:

image

This would seem to imply that the issue is not just from the terminal's color scheme, but something to do with how the terminal is processing the escape characters.

Until we have a long-term fix, users can set FORCE_COLOR=0 to disable all color:

FORCE_COLOR=0 npx typewriter init

Which isn't ideal, but will at least be functional:

image

Kotlin Multiplatform support

First of all I want to start off by saying I LOVE this feature. I think it's absolutely brilliant and I'm super excited to see it push analytics forward!

I've got a (probably very complicated) feature request:

I'm currently working on a project that uses Kotlin Multiplatform. I know that Segment isn't natively supported in KM, but it would be really cool if there was some way to generate just the types for the analytic events (in Kotlin), without actually sending the event. Then we could offload sending the actual analytic to the native Segment libraries in Android, iOS and the web and just use the type safety to ensure we're building the right event payloads.

Anyways, just a thought and I love the library!

Generate enum as enum for Java

Hi 👋
using the following schema for a test event:
{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "labels": { "section": "auth" }, "description": "Testing Events with accepted values", "properties": { "context": { "id": "/properties/context" }, "traits": { "type": "object", "id": "/properties/traits" }, "properties": { "type": "object", "properties": { "backpack_contents": { "description": "What are you taking on your trip", "id": "/properties/properties/properties/backpack_contents", "properties": { "item_name": { "description": "Item name", "enum": [ "food", "raincoat", "salami", "tootbrush" ], "id": "/properties/properties/properties/backpack_contents/properties/item_name", "type": "string" }, "weight": { "description": "How heavy is the backpack", "id": "/properties/properties/properties/backpack_contents/properties/weight", "type": "integer" } }, "required": [], "type": "object" }, "heading": { "description": "Heading direction", "enum": [ "east", "north", "south", "west" ], "id": "/properties/properties/properties/heading", "type": "string" }, "trip_name": { "description": "A descriptive name for the trip, example: \"Road trip to Vegas\"", "id": "/properties/properties/properties/trip_name", "pattern": "([A-Z])\\w+", "type": "string" } }, "id": "/properties/properties" } } }

the generated code for Java, TestEvent.Builder takes heading as a String. Ideally this should be an enum with 4 options so clients shouldn't have these values hard-coded, which would also prevent other values to be added.

Server-side Java Support

Similar to: #91

This issue tracks support for server-side Java clients that are using analytics-java, rather than just supporting analytics-android.

Gif not working

The gif in the readme, which is helpful for explaining what Typewriter does is busted :-(

npx typewriter init on windows doesn't pick up token - Error: Token script failed

When running..

npx typewriter --debug

on a windows machine, I get the error...

× Error: Token script failed
→ Tried running: 'echo "DOESNTWORK"'
→ The system cannot find the path specified.

It works fine for my co-workers who are using a linux based system.

Is there something I am doing wrong when running this from windows?

I'm following the same instructions in the documentation here.

https://segment.com/docs/protocols/apis-and-extensions/typewriter/#token-script

Screenshot of error

image

Full log..

`npx typewriter --debug
npx: installed 159 in 7.127s

... Loading Tracking Plan...
↪ Downloading the latest version from Segment...
Removing generated files...
Generating client...
Trace: {
isWrappedError: true,
description: 'Token script failed',
notes: [

E:\vs\growflow-raptor-backend\frontend>npx typewriter --debug
npx: installed 159 in 5.375s

... Loading Tracking Plan...
↪ Downloading the latest version from Segment...
Removing generated files...
Generating client...
Trace: {
isWrappedError: true,
description: 'Token script failed',
notes: [
Tried running: 'echo "DOESNTWORK"',
'The system cannot find the path specified.\r'
],
error: Error: Command failed: cd ./; echo "DOESNTWORK"
The system cannot find the path specified.

  at ChildProcess.exithandler (child_process.js:308:12)
  at ChildProcess.emit (events.js:315:20)
  at maybeClose (internal/child_process.js:1048:16)
  at Process.ChildProcess._handle.onexit (internal/child_process.js:288:5) {
killed: false,
code: 1,
signal: null,
cmd: 'cd ./; echo "DOESNTWORK"',
stdout: '',
stderr: 'The system cannot find the path specified.\r\n'

}
}
at ErrorBoundary. (C:\Users\tmwil\AppData\Roaming\npm-cache_npx\39988\node_modules\typewriter\dist\src\cli\commands\error.js:89:25)
at Generator.next ()
at C:\Users\tmwil\AppData\Roaming\npm-cache_npx\39988\node_modules\typewriter\dist\src\cli\commands\error.js:27:71
at new Promise ()
at __awaiter (C:\Users\tmwil\AppData\Roaming\npm-cache_npx\39988\node_modules\typewriter\dist\src\cli\commands\error.js:23:12)
at ErrorBoundary.reportError (C:\Users\tmwil\AppData\Roaming\npm-cache_npx\39988\node_modules\typewriter\dist\src\cli\commands\error.js:82:40)
at ErrorBoundary. (C:\Users\tmwil\AppData\Roaming\npm-cache_npx\39988\node_modules\typewriter\dist\src\cli\commands\error.js:101:24)
at Generator.next ()
at C:\Users\tmwil\AppData\Roaming\npm-cache_npx\39988\node_modules\typewriter\dist\src\cli\commands\error.js:27:71
at new Promise ()

× Error: Token script failed
→ Tried running: 'echo "DOESNTWORK"'
→ The system cannot find the path specified.

If you are unable to resolve this issue, open an issue on GitHub
(​https://github.com/segmentio/typewriter/issues/new​). Please include that you
are using version 7.4.1 of Typewriter.
× Error: Token script failed
→ Tried running: 'echo "DOESNTWORK"'
→ The system cannot find the path specified.

If you are unable to resolve this issue, open an issue on GitHub
(​https://github.com/segmentio/typewriter/issues/new​). Please include that you
are using version 7.4.1 of Typewriter.`

Does not work with React 17.

  1. Create an application with create-react-app.
  2. Add typewriter yarn add -D typewriter
  3. Run typewriter init npx typewriter init

You will get this error:

TypeError: setRawMode is not a function
    at SelectInput.componentDidMount (/Users/djohnston/git/typewriter/node_modules/ink-select-input/build/SelectInput.js:161:5)
    at jg (/Users/djohnston/git/typewriter/node_modules/typewriter/node_modules/react-reconciler/cjs/react-reconciler.production.min.js:152:160)
    at exports.unstable_runWithPriority (/Users/djohnston/git/typewriter/node_mo

  ✖ Error: An unexpected error occurred.
   → setRawMode is not a function

  If you are unable to resolve this issue, open an issue on GitHub. Please inclu
de
   that you are using version 7.4.1 of Typewriter.

Downgrading to React 16 solves this issue.

Android - Duplicate classes

In the case of a feature proposal ✍️

Our team is using typewriter v7 for android. Thank you for publishing this useful tool.

One thing we've noticed is that we re-use certain objects throughout our analytics implementation (as recommended in Segment Academy). For example, we have a notion of Quantity with attributes number and type that gets re-used in several analytics events.

It could be represented like:

data class Quantity {
  val number: Int,
  val type: String
}

We've observed that typewriter will generate identical classes Quantity, Quantity1, Quantity2, etc. for every separate event that uses the notion of Quantity. Not a big deal, but it would be a nice thing if typewriter was smart enough to consolidate these identical classes into one shared class just to make usage of generated typewriter code easier to grok and reduce in bloat.

Thanks again for the great tool, and for considering our suggestion.

Cannot find namespace 'SegmentAnalytics'.

Repro:

  1. Create a new create-react-app with the TypeScript template
  2. Change version down to 16. (see: #209)
  3. Add typewriter yarn add -D typewriter
  4. Init typewriter npx typewriter init Initialise the typewriter boilerplate in src/analytics

Open src/analytics/index.ts - You will see:

let analytics: () => SegmentAnalytics.AnalyticsJS | undefined = () => {
	return window.analytics
}

With the error:

Cannot find namespace 'SegmentAnalytics'.ts(2503)

Customizable prefix when generating the iOS client

Hey lovely typewriter team,

I am actually not completely sure if this is a bug report or a feature request. I'll just write it as a feature request. Please feel free to correct me if this is something that should actually work.

My current situation

I am currently trying to use typewriter in an iOS project. Unfortunately there is a name collision.

  • In the Analytics/Segment iOS SDK there is a SEGContext class.
  • In our test plan there is a property (I hope that's how you call them) called context. When I use npx typewriter it generates a second SEGContext class.

Proposal

We could make the SEG prefix configurable in the typewriter.yml configuration file. In that case I could change the SEG prefix to e.g. SEGGenerated which would lead to a SEGGeneratedContext class to be generated an thus resolve the collision.

Alternatives

  • Instead of making the prefix configurable, we could also change the prefix for the generated files (e.g. to SEGG) to prevent collisions
  • I saw there already is some kind of mechanism to resolve collisions (some duplicate types have a number appended). Maybe there is a way to leverage this as well?

Looking forward to your feedback and ideas!

ajv@7+ fails on local development

After generating a local instance of Typewriter files for analytics.js in Typescript, instructions are provided to include ajv for runtime errors in the ./analytics/index.ts file.

/**
 * Ajv is a peer dependency for development builds. It's used to apply run-time validation
 * to message payloads before passing them on to the underlying analytics instance.
 *
 * Note that the production bundle does not depend on Ajv.
 *
 * You can install it with: `npm install --save-dev ajv`.
 */

When you install the latest version of ajv though, I see the following errors when bundling an application with webpack:

ERROR in ./analytics/index.ts 81:20-69
  Module not found: Error: Can't resolve 'ajv/lib/refs/json-schema-draft-04.json' in ...

Proposal

Either the note needs to include details about which avj@6 as the correct version or ajv needs to be upgraded as a dev dependency.

Interactive Tracking Plan Update Support: `typewriter update --interactive`

This issue tracks progress towards adding an interactive variant of typewriter update that allows you to select which updates to apply, if there are multiple.

Currently, when you run typewriter update (or typewriter -- it's the default command), it'll pull down all changes, s.t. your plan.json matches your Tracking Plan from segment.com. However, with large teams, this often pulls in unrelated changes that you have to manually prune from your plan.json.

Ideally, you can select the subset of changes that are relevant to you. I imagine two ways:

  • By label ("apply all changes with team:protocols")
  • By individual event ("select and apply these 3 events")

TypeError: Cannot read property 'properties' of undefined

→ ./node_modules/.bin/typewriter --version
6.1.4

→ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.14.6
BuildVersion:	18G87

I'm generating a client from the following (truncated) tracking plan:

tracking-plan.json

{
  "events": [
    {
      "description": "The user has signed up for our Newsletter",
      "name": "Newsletter Signup",
      "rules": {
        "$schema": "http://json-schema.org/draft-04/schema#",
        "properties": {
          "context": {},
          "properties": {
            "properties": {
              "signup_type": {
                "description": "The type of form that was used to sign up for email",
                "enum": ["footer", "callout"]
              }
            },
            "required": ["signup_type"],
            "type": "object"
          },
          "traits": {}
        },
        "type": "object"
      },
      "version": 1
    }
  ],
  "name": "name"
}

Using the above schema as input to the gen-js handler, I receive the following client:

./analytics/generated/index.js

export default class Analytics {
  /**
   * Instantiate a wrapper around an analytics library instance
   * @param {Analytics} analytics The analytics.js library to wrap
   * @param {Object} [options] Optional configuration of the Typewriter client
   * @param {function} [options.onError] Error handler fired when run-time validation errors
   *     are raised.
   */
  constructor(analytics, options = {}) {
    if (!analytics) {
      throw new Error("An instance of analytics.js must be provided");
    }
    this.analytics = analytics || { track: () => null };
    this.onError =
      options.onError ||
      (error => {
        throw new Error(JSON.stringify(error, null, 2));
      });
  }
  addTypewriterContext(context = {}) {
    return {
      ...context,
      typewriter: {
        name: "gen-js",
        version: "6.1.4"
      }
    };
  }
  newsletterSignup(props = {}, options = {}, callback) {
    var validate = function(
      data,
      dataPath,
      parentData,
      parentDataProperty,
      rootData
    ) {
      "use strict";
      var vErrors = null;
      var errors = 0;
      if (data && typeof data === "object" && !Array.isArray(data)) {
        var errs__0 = errors;
        var valid1 = true;
        var data1 = data.properties;
        if (data1 !== undefined) {
          var errs_1 = errors;
          if (data1 && typeof data1 === "object" && !Array.isArray(data1)) {
            var errs__1 = errors;
            var valid2 = true;
            if (data1.signup_type === undefined) {
              valid2 = false;
              var err = {
                keyword: "required",
                dataPath: (dataPath || "") + ".properties",
                schemaPath: "#/properties/properties/required",
                params: { missingProperty: "signup_type" },
                message: "should have required property 'signup_type'"
              };
              if (vErrors === null) vErrors = [err];
              else vErrors.push(err);
              errors++;
            } else {
              var errs_2 = errors;
              var schema2 =
                validate.schema.properties.properties.properties.signup_type
                  .enum;
              var valid2;
              valid2 = false;
              for (var i2 = 0; i2 < schema2.length; i2++)
                if (equal(data1.signup_type, schema2[i2])) {
                  valid2 = true;
                  break;
                }
              if (!valid2) {
                var err = {
                  keyword: "enum",
                  dataPath: (dataPath || "") + ".properties.signup_type",
                  schemaPath:
                    "#/properties/properties/properties/signup_type/enum",
                  params: { allowedValues: schema2 },
                  message: "should be equal to one of the allowed values"
                };
                if (vErrors === null) vErrors = [err];
                else vErrors.push(err);
                errors++;
              }
              var valid2 = errors === errs_2;
            }
          } else {
            var err = {
              keyword: "type",
              dataPath: (dataPath || "") + ".properties",
              schemaPath: "#/properties/properties/type",
              params: { type: "object" },
              message: "should be object"
            };
            if (vErrors === null) vErrors = [err];
            else vErrors.push(err);
            errors++;
          }
          var valid1 = errors === errs_1;
        }
      } else {
        var err = {
          keyword: "type",
          dataPath: (dataPath || "") + "",
          schemaPath: "#/type",
          params: { type: "object" },
          message: "should be object"
        };
        if (vErrors === null) vErrors = [err];
        else vErrors.push(err);
        errors++;
      }
      validate.errors = vErrors;
      return errors === 0;
    };
    if (!validate({ properties: props })) {
      this.onError({
        eventName: "Newsletter Signup",
        validationErrors: validate.errors
      });
      return;
    }
    this.analytics.track(
      "Newsletter Signup",
      props,
      {
        ...options,
        context: this.addTypewriterContext(options.context)
      },
      callback
    );
  }
}

When running in the browser, I receive the following error:

import Analytics from '../analytics/generated'
...
const analytics = new Analytics(window.analytics)
analytics.newsletterSignup({signup_type: 'footer'})
...
TypeError: Cannot read property 'properties' of undefined
validate
./analytics/generated/index.js:63

| 63 |   var schema2 =
| 64 | >    validate.schema.properties.properties.properties.signup_type
| 65 |       .enum

Does the ./generated/index.js client look correct? I believe the tracking plan is in the correct format. I'm using the undocumented Node.js API to interact with the library. I don't believe that this would result in an incorrect output however. I'd be glad to contribute if this is indeed a bug.

Proxy use and IE11 Support

We've been happily using typewriter almost a year now(since Feb 2019). We have a business requirement to support IE11. Since updating to [email protected], we've needed to add a polyfill to use this library due to its use of Proxy.

We've temporarily added a polyfill, but this is not a 1:1 match in terms of functionality with the native Proxy. Is there any way to refactor the generated code to not use this non-standard feature or to include a polyfill and/or warning for browser support?

[FEATURE] Tracking property Pattern validation

We'e recently started integrating Typewriter @ Buffer - it's been frictionless to setup, thanks for the great work!

I'm currently working on the Android side of things, one thing that I think would be great to have in place is pattern validation. For example, in some of our tracking events we have the following declared:

- name: product
  ...
  type: string
  pattern: publish|analyze|remix

it would be great for Typewriter to throw an error if the value being sent does not match the required value. Are there any plans to add this? I was thinking of taking a look at contributing this, but wasn't sure if it was in the pipeline already 🙂

Thanks!

Speed up CI tests

We can speed up our CI tests by:

  • Explore caching pod install with pod check or a Pods cache of just analytics-ios or git checkout segmentio/analytics-ios
  • Parallelizing dev and prod tests

Unable to create a local dev build for typewriter

Issue

Hey. I'm trying to create a local dev build for typewriter using yarn dev build as specified in the docs. I'm getting this error:

yarn run v1.22.10
$ TS_NODE_FILES=true NODE_ENV=development ts-node ./src/cli build

/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:434
    return new TSError(diagnosticText, diagnosticCodes)
           ^
TSError: ⨯ Unable to compile TypeScript:
src/cli/index.tsx:10:10 - error TS2440: Import declaration conflicts with local declaration of 'CLIArguments'.

10 import { CLIArguments } from './index'
            ~~~~~~~~~~~~

    at createTSError (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:434:12)
    at reportTSError (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:438:19)
    at getOutput (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:578:36)
    at Object.compile (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:775:32)
    at Module.m._compile (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:858:43)
    at Module._extensions..js (node:internal/modules/cjs/loader:1131:10)
    at Object.require.extensions.<computed> [as .tsx] (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:861:12)
    at Module.load (node:internal/modules/cjs/loader:967:32)
    at Function.Module._load (node:internal/modules/cjs/loader:807:14)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:12)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

SO If I'm commenting out line10 in index.tsx (import { CLIArguments } from './index') I'm avoiding this error but I'm running into a new one:

yarn run v1.22.10
$ TS_NODE_FILES=true NODE_ENV=development ts-node ./src/cli build

/Users/alexmarchis1/Work/typewriter/node_modules/yoga-layout-prebuilt/yoga-layout/build/Release/nbind.js:53
        throw ex;
        ^
TSError: ⨯ Unable to compile TypeScript:
src/cli/config/config.ts:48:24 - error TS2345: Argument of type 'string | object | undefined' is not assignable to parameter of type 'object'.
  Type 'undefined' is not assignable to type 'object'.

48  return validateConfig(rawConfig)
                          ~~~~~~~~~

    at createTSError (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:434:12)
    at reportTSError (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:438:19)
    at getOutput (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:578:36)
    at Object.compile (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:775:32)
    at Module.m._compile (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:858:43)
    at Module._extensions..js (node:internal/modules/cjs/loader:1131:10)
    at Object.require.extensions.<computed> [as .ts] (/Users/alexmarchis1/Work/typewriter/node_modules/ts-node/src/index.ts:861:12)
    at Module.load (node:internal/modules/cjs/loader:967:32)
    at Function.Module._load (node:internal/modules/cjs/loader:807:14)
    at Module.require (node:internal/modules/cjs/loader:991:19) {
  diagnosticText: "\x1B[96msrc/cli/config/config.ts\x1B[0m:\x1B[93m48\x1B[0m:\x1B[93m24\x1B[0m - \x1B[91merror\x1B[0m\x1B[90m TS2345: \x1B[0mArgument of type 'string | object | undefined' is not assignable to parameter of type 'object'.\n" +
    "  Type 'undefined' is not assignable to type 'object'.\n" +
    '\n' +
    '\x1B[7m48\x1B[0m  return validateConfig(rawConfig)\n' +
    '\x1B[7m  \x1B[0m \x1B[91m                       ~~~~~~~~~\x1B[0m\n',
  diagnosticCodes: [ 2345 ]
}
error Command failed with exit code 7.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Is there something I'm doing wrong or missing? Am I missing some dependencies or the installed versions are not the expected ones?
Any help is appreciated.
Thank you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.