Skip to content

Instantly share code, notes, and snippets.

View kentcdodds's full-sized avatar
馃
working hard to make the world better with software

Kent C. Dodds kentcdodds

馃
working hard to make the world better with software
View GitHub Profile
@kentcdodds
kentcdodds / tag.js
Created August 9, 2021 20:34
Tag subscribers of a ConvertKit sequence with a tag
const fetch = require('make-fetch-happen').defaults({
cacheManager: './node_modules/.cache/make-fetch-happen',
})
// add a .env file that has this in it:
// CONVERT_KIT_API_KEY=some_api_key
// CONVERT_KIT_API_SECRET=some_api_secret
require('dotenv').config()
const {CONVERT_KIT_API_KEY, CONVERT_KIT_API_SECRET} = process.env
@kentcdodds
kentcdodds / most-popular-posts.ts
Created July 30, 2021 19:09
Prisma is awesome. I love this!
@kentcdodds
kentcdodds / cachified.ts
Last active April 19, 2023 04:54
Turn any function into a cachified one. With forceFresh support and value checking (for when the data type changes). This uses redis, but you could change it to use whatever you want.
type CacheMetadata = {
createdTime: number
maxAge: number | null
expires: number | null
}
function shouldRefresh(metadata: CacheMetadata) {
if (metadata.maxAge) {
return Date.now() > metadata.createdTime + metadata.maxAge
}
// Menu: Daily Story
// Description: Write a quick story
// Author: Kent C. Dodds
// Shortcut: command option control o
// Twitter: @kentcdodds
const dateFns = await npm('date-fns')
const filenamify = await npm('filenamify')
const prettier = await npm('prettier')
@kentcdodds
kentcdodds / parse-multipart-form-data.ts
Created July 14, 2021 21:13
I thought I needed this but turns out I didn't. None of the existing solutions worked well for me so I built this. Maybe it'll be useful someday...
import {typedBoolean} from './misc'
function headerValuesAsObject(headerValue: string) {
const valuesAsObject: Record<string, string> = Object.fromEntries(
headerValue
.split(', ')
.filter(h => h.includes('='))
.map(h => {
const [key, valueString] = h.split('=')
if (!valueString) return []
@kentcdodds
kentcdodds / index.js
Created July 9, 2021 21:40
Parsing HTML or Markdown and processing both as markdown then outputting to HTML
const unified = require('unified')
const parseMarkdown = require('remark-parse')
const parseHtml = require('rehype-parse')
const remark2rehype = require('remark-rehype')
const rehype2remark = require('rehype-remark')
const rehypeStringify = require('rehype-stringify')
const visit = require('unist-util-visit')
async function go() {
const inputString = `
// Menu: ConvertKit > Lookup
// Description: Query convertkit
// Author: Kent C. Dodds
// Twitter: @kentcdodds
const CONVERT_KIT_API_SECRET = await env('CONVERT_KIT_API_SECRET')
const CONVERT_KIT_API_KEY = await env('CONVERT_KIT_API_KEY')
const query = await arg('query')
let url
@kentcdodds
kentcdodds / rmx-snippet-output.tsx
Created June 30, 2021 21:57
Remix snippet for a new module
import * as React from 'react'
import type {LoaderFunction, ActionFunction} from 'remix'
import {json, redirect, useRouteData, Form} from 'remix'
type LoaderData = {}
export const loader: LoaderFunction = async () => {
const data: LoaderData = {}
return json(data)
}
@kentcdodds
kentcdodds / create-simple-context.tsx
Last active September 24, 2021 08:42
A simple context creator that doesn't allow any logic. It's 100% just to make it easy to pass a value from a parent to all children, specifically useful for remix where you just want a loader's data to be accessible anywhere else in your tree.
function createSimpleContext<ContextType>(name: string) {
const defaultValue = Symbol(`Default ${name} context value`)
const Context =
React.createContext<ContextType | null | typeof defaultValue>(defaultValue)
Context.displayName = name
function useValue() {
const user = React.useContext(Context)
if (user === defaultValue) {
throw new Error(`use${name} must be used within ${name}Provider`)
// Menu: Cloudinary upload
// Description: Upload an image to cloudinary
// Shortcut: command option control c
// Author: Kent C. Dodds
// Twitter: @kentcdodds
import path from 'path'
const cloudinaryCloudName = await env('CLOUDINARY_CLOUD_NAME')
const cloudinaryKey = await env('CLOUDINARY_API_KEY')