From d60137c8c8e6ca5fef44f2610886795aa929506b Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Sun, 27 Aug 2023 20:59:38 +0100 Subject: [PATCH] style: Improve eslint setup --- .eslintrc.js | 27 ++++++- package.json | 2 + posthog-core/test/posthog.capture.spec.ts | 2 +- posthog-node/src/feature-flags.ts | 5 +- posthog-react-native/jest.config.js | 6 +- posthog-react-native/package.json | 1 + posthog-react-native/src/PostHogProvider.tsx | 11 +-- .../src/hooks/useNavigationTracker.ts | 12 ++-- yarn.lock | 72 +++++++++++++++++++ 9 files changed, 117 insertions(+), 21 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 10b2273e..55a9b8b6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,13 @@ -/* global module */ +const extend = [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react/recommended', + 'plugin:react-hooks/recommended', + 'prettier', +] + +const plugins = ['prettier', 'react', '@typescript-eslint', 'eslint-plugin-react-hooks', 'eslint-plugin-jest'] + module.exports = { ignorePatterns: ['node_modules', 'examples', 'lib'], env: { @@ -10,10 +19,11 @@ module.exports = { version: 'detect', }, }, - extends: ['plugin:@typescript-eslint/recommended', 'plugin:react/recommended', 'prettier'], + extends: extend, globals: { Atomics: 'readonly', SharedArrayBuffer: 'readonly', + module: 'readonly', }, parser: '@typescript-eslint/parser', parserOptions: { @@ -23,7 +33,7 @@ module.exports = { ecmaVersion: 2018, sourceType: 'module', }, - plugins: ['prettier', 'react', '@typescript-eslint'], + plugins, rules: { 'react/prop-types': [0], 'react/no-unescaped-entities': [0], @@ -61,6 +71,8 @@ module.exports = { ], }, ], + 'no-empty': 'off', + 'no-constant-condition': 'off', }, overrides: [ { @@ -96,6 +108,15 @@ module.exports = { '@typescript-eslint/no-var-requires': 'off', }, }, + { + files: ['*.test.ts', '*.test.tsx', '*.spec.ts', '*.spec.tsx'], + env: { + jest: true, + node: true, + browser: true, + es6: true, + }, + }, ], reportUnusedDisableDirectives: true, } diff --git a/package.json b/package.json index a0152ede..6c71373d 100644 --- a/package.json +++ b/package.json @@ -37,8 +37,10 @@ "babel-jest": "^28.1.3", "eslint": "^8.19.0", "eslint-config-prettier": "^8.5.0", + "eslint-plugin-jest": "^27.2.3", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-react": "^7.30.1", + "eslint-plugin-react-hooks": "^4.6.0", "husky": "^8.0.1", "jest": "^28.1.3", "jest-environment-jsdom": "^28.1.3", diff --git a/posthog-core/test/posthog.capture.spec.ts b/posthog-core/test/posthog.capture.spec.ts index e8925820..b6bc01e4 100644 --- a/posthog-core/test/posthog.capture.spec.ts +++ b/posthog-core/test/posthog.capture.spec.ts @@ -19,7 +19,7 @@ describe('PostHog Core', () => { expect(mocks.fetch).toHaveBeenCalledTimes(1) const [url, options] = mocks.fetch.mock.calls[0] - expect(url).toMatch(/^https:\/\/app\.posthog\.com\/e\/\?ip=1&_=[0-9]+&v=[0-9\.a-z\-]+$/) + expect(url).toMatch(/^https:\/\/app\.posthog\.com\/e\/\?ip=1&_=[0-9]+&v=[0-9.a-z-]+$/) expect(options.method).toBe('POST') const body = parseBody(mocks.fetch.mock.calls[0]) diff --git a/posthog-node/src/feature-flags.ts b/posthog-node/src/feature-flags.ts index 30396d78..a2442727 100644 --- a/posthog-node/src/feature-flags.ts +++ b/posthog-node/src/feature-flags.ts @@ -424,8 +424,6 @@ class FeatureFlagsPoller { try { return await this.fetch(url, options) - } catch (err) { - throw err } finally { clearTimeout(abortTimeout) } @@ -487,13 +485,14 @@ function matchProperty( case 'lte': return typeof overrideValue == typeof value && overrideValue <= value case 'is_date_after': - case 'is_date_before': + case 'is_date_before': { const parsedDate = convertToDateTime(value) const overrideDate = convertToDateTime(overrideValue) if (operator === 'is_date_before') { return overrideDate < parsedDate } return overrideDate > parsedDate + } default: console.error(`Unknown operator: ${operator}`) return false diff --git a/posthog-react-native/jest.config.js b/posthog-react-native/jest.config.js index 9308e00d..ac404aef 100644 --- a/posthog-react-native/jest.config.js +++ b/posthog-react-native/jest.config.js @@ -3,15 +3,13 @@ module.exports = { roots: [''], testEnvironment: 'node', transform: { - '^.+\\.ts?$': 'ts-jest', + '^.+\\.ts$': 'ts-jest', }, moduleFileExtensions: ['ts', 'js', 'json', 'node', 'tsx'], collectCoverage: true, clearMocks: true, coverageDirectory: 'coverage', - testPathIgnorePatterns: ['node_modules', 'examples'], + testPathIgnorePatterns: ['/lib/', 'node_modules', 'examples'], fakeTimers: { enableGlobally: true }, transformIgnorePatterns: [], - - testPathIgnorePatterns: ['/lib/', '/node_modules/'], } diff --git a/posthog-react-native/package.json b/posthog-react-native/package.json index ba2b3793..07795552 100644 --- a/posthog-react-native/package.json +++ b/posthog-react-native/package.json @@ -16,6 +16,7 @@ "@babel/cli": "^7.19.3", "@react-native-async-storage/async-storage": "^1.17.10", "@react-navigation/native": "^5.0.10", + "@types/jest": "^28.1.5", "@types/react-native": "^0.69.1", "expo": "^45.0.6", "expo-application": "^4.0.0", diff --git a/posthog-react-native/src/PostHogProvider.tsx b/posthog-react-native/src/PostHogProvider.tsx index 85192c2d..c52d9087 100644 --- a/posthog-react-native/src/PostHogProvider.tsx +++ b/posthog-react-native/src/PostHogProvider.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react' +import React, { useCallback, useEffect, useMemo, useState } from 'react' import { GestureResponderEvent, StyleProp, View, ViewStyle } from 'react-native' import { PostHog, PostHogOptions } from './posthog-rn' import { autocaptureFromTouchEvent } from './autocapture' @@ -39,7 +39,10 @@ export const PostHogProvider = ({ // Check if the client is a promise and resolve it if so const [posthog, setPosthog] = useState(client instanceof Promise ? undefined : client) - const autocaptureOptions = autocapture && typeof autocapture !== 'boolean' ? autocapture : {} + const autocaptureOptions = useMemo( + () => (autocapture && typeof autocapture !== 'boolean' ? autocapture : {}), + [autocapture] + ) const captureAll = autocapture === true const captureNone = autocapture === false @@ -65,7 +68,7 @@ export const PostHogProvider = ({ } else if (!posthog && apiKey) { PostHog.initAsync(apiKey, options).then(setPosthog) } - }, [client, apiKey]) + }, [client, apiKey, posthog, options]) useEffect(() => { if (!posthog) { @@ -86,7 +89,7 @@ export const PostHogProvider = ({ autocaptureFromTouchEvent(e, posthog, autocaptureOptions) } }, - [posthog, autocapture] + [captureTouches, posthog, autocaptureOptions] ) return ( diff --git a/posthog-react-native/src/hooks/useNavigationTracker.ts b/posthog-react-native/src/hooks/useNavigationTracker.ts index e68dddac..cabc6ad1 100644 --- a/posthog-react-native/src/hooks/useNavigationTracker.ts +++ b/posthog-react-native/src/hooks/useNavigationTracker.ts @@ -1,4 +1,4 @@ -import { useEffect } from 'react' +import { useCallback, useEffect } from 'react' import { OptionalReactNativeNavigation } from '../optional/OptionalReactNativeNavigation' import type { PostHog } from '../posthog-rn' import { PostHogAutocaptureNavigationTrackerOptions } from '../types' @@ -13,14 +13,14 @@ function _useNavigationTracker(options?: PostHogAutocaptureNavigationTrackerOpti const posthog = client || contextClient if (!OptionalReactNativeNavigation) { - // NOTE: This is taken care of by the export but we keep this here for TS - return + // NOTE: This is taken care of by the export, but we keep this here for TS + throw new Error('No OptionalReactNativeNavigation') } const routes = OptionalReactNativeNavigation.useNavigationState((state) => state?.routes) const navigation = OptionalReactNativeNavigation.useNavigation() - const trackRoute = (): void => { + const trackRoute = useCallback((): void => { if (!posthog) { return } @@ -45,7 +45,7 @@ function _useNavigationTracker(options?: PostHogAutocaptureNavigationTrackerOpti const properties = options?.routeToProperties?.(currentRouteName, params) posthog.screen(currentRouteName, properties) } - } + }, [navigation, options, posthog]) useEffect(() => { // NOTE: The navigation stacks may not be fully rendered initially. This means the first route can be missed (it doesn't update useNavigationState) @@ -55,7 +55,7 @@ function _useNavigationTracker(options?: PostHogAutocaptureNavigationTrackerOpti return } trackRoute() - }, [routes]) + }, [routes, trackRoute]) } export const useNavigationTracker = OptionalReactNativeNavigation diff --git a/yarn.lock b/yarn.lock index ddb463b2..a3dc7852 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1253,6 +1253,13 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + "@eslint/eslintrc@^1.3.0": version "1.3.0" resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz" @@ -2542,6 +2549,11 @@ resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== +"@types/semver@^7.3.12": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" + integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== + "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" @@ -2611,6 +2623,14 @@ "@typescript-eslint/types" "5.30.7" "@typescript-eslint/visitor-keys" "5.30.7" +"@typescript-eslint/scope-manager@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" + integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + "@typescript-eslint/type-utils@5.30.7": version "5.30.7" resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.7.tgz" @@ -2625,6 +2645,11 @@ resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.7.tgz" integrity sha512-ocVkETUs82+U+HowkovV6uxf1AnVRKCmDRNUBUUo46/5SQv1owC/EBFkiu4MOHeZqhKz2ktZ3kvJJ1uFqQ8QPg== +"@typescript-eslint/types@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" + integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== + "@typescript-eslint/typescript-estree@5.30.7": version "5.30.7" resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.7.tgz" @@ -2638,6 +2663,19 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" + integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + "@typescript-eslint/utils@5.30.7": version "5.30.7" resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.7.tgz" @@ -2650,6 +2688,20 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" +"@typescript-eslint/utils@^5.10.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" + integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + "@typescript-eslint/visitor-keys@5.30.7": version "5.30.7" resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.7.tgz" @@ -2658,6 +2710,14 @@ "@typescript-eslint/types" "5.30.7" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" + integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== + dependencies: + "@typescript-eslint/types" "5.62.0" + eslint-visitor-keys "^3.3.0" + "@urql/core@2.3.6": version "2.3.6" resolved "https://registry.npmjs.org/@urql/core/-/core-2.3.6.tgz" @@ -4252,6 +4312,13 @@ eslint-config-prettier@^8.5.0: resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz" integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== +eslint-plugin-jest@^27.2.3: + version "27.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz#6f8a4bb2ca82c0c5d481d1b3be256ab001f5a3ec" + integrity sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ== + dependencies: + "@typescript-eslint/utils" "^5.10.0" + eslint-plugin-prettier@^4.2.1: version "4.2.1" resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz" @@ -4259,6 +4326,11 @@ eslint-plugin-prettier@^4.2.1: dependencies: prettier-linter-helpers "^1.0.0" +eslint-plugin-react-hooks@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== + eslint-plugin-react@^7.30.1: version "7.30.1" resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.30.1.tgz"