Skip to content

Instantly share code, notes, and snippets.

View fsubal's full-sized avatar

fsubal fsubal

View GitHub Profile
@fsubal
fsubal / AppUrl.ts
Last active February 2, 2025 09:44
import { compile } from 'path-to-regexp'
type UrlParams = Record<string, string | number>
function normarizeUrlParams(input: UrlParams): Record<string, string> {
return Object.fromEntries(
Object.entries(input).map(([key, value]) => [key, value.toString()])
)
}
module AttrReaderGuard
extend ActiveSupport::Concern
class InvalidError < ArgumentError
PREFIX = '[attr_reader_guard!]:'
def initialize(subject, predicate)
super [PREFIX, subject, predicate].join(' ')
end
end
export class Unreachable extends TypeError {
static assert(value: never): never {
throw new this(value)
}
static silent(value: never): void {
void value
}
constructor(value: never) {
@fsubal
fsubal / cx.ts
Last active December 14, 2024 04:03
type ClassNameValue = string | number | false | undefined | null | ClassNameValue[] | { [className: string]: boolean }
function cx(...values: ClassNameValue[]) {
const classNames: string[] = []
for (const value of values) {
if (!value) {
continue
}
if (Array.isArray(value)) {
import Papa from 'papaparse'
class Csv {
constructor(readonly header: string[], readonly rows: string[][]) {}
static parse(csv: string) {
const [header, ...rows] = Papa.parse(csv.trim(), { header: false })
return new this(header, rows)
}
export class AnswerEvent extends CustomEvent<FormData> {
static readonly type = 'async-dialog:answer'
constructor(detail: FormData) {
super(AnswerEvent.type, { detail })
}
get answer() {
return this.detail.get('answer')?.toString()
}
import Ajv, { JSONSchemaType, ErrorObject } from 'ajv'
import { FromSchema } from 'json-schema-to-ts'
interface AggregatedValidationError extends AggregateError {
errors: ErrorObject[]
}
/**
* ajvは全スキーマをキャッシュするので、インスタンスごとにnewせず、使い回す
*/
class SlackNotification
class UnknownSlackChannel < StandardError; end
WEBHOOK_URLS = Rails.configuration.x.slack_webhook_urls
def initialize(webhook_url:)
@notifier = Slack::Notifier.new(webhook_url)
end
def self.for_channel(channel_name)
@fsubal
fsubal / AppError.ts
Last active September 15, 2024 10:02
/**
* `try ... catch`で`any`や`unknown`が来たときに、こいつに渡すとすべてをいい感じにしてくれる。
*
* ただし、あくまで単一のエラーに対して使う想定。
* 複数のエラーをまとめる用途には、標準の`AggregateError`を使うこと。
*
* @see https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/AggregateError
*
* @example
* ```ts
import { useMemo } from 'react'
interface Props {
value?: unknown
indent?: number
}
export function useVarDump(value: unknown, indent = 2) {
const json = useMemo(() => {
try {