Refactor (1)

This commit is contained in:
2025-09-19 18:54:12 +09:00
committed by cannorin
parent 6b15542c40
commit c3b1bf39a4
26 changed files with 1684 additions and 105 deletions

View File

@@ -1,45 +1,3 @@
interface String {
concat<S extends string>(string: S): `${this}${S}`;
concat<S1 extends string, S2 extends string>(
s1: S1,
s2: S2,
): `${this}${S1}${S2}`;
startsWith<S extends string>(searchString: S): this is `${S}${string}`;
endsWith<S extends string>(searchString: S): this is `${string}${S}`;
includes<S extends string>(
searchString: S,
position?: number,
): this is `${string}${S}${string}`;
}
type LiteralUnionLike<T> = T extends string
? T extends ""
? T
: T extends `${T}${T}`
? never
: T
: T extends number
? `${T}0` extends `${number}`
? T
: never
: T extends null | undefined
? T
: never;
interface Array<T> {
includes(
searchElement: T extends LiteralUnionLike<T> ? unknown : never,
fromIndex?: number,
): searchElement is T extends LiteralUnionLike<T> ? T : never;
}
interface ReadonlyArray<T> {
includes(
searchElement: T extends LiteralUnionLike<T> ? unknown : never,
fromIndex?: number,
): searchElement is T extends LiteralUnionLike<T> ? T : never;
}
declare module "*&enhanced" {
import type { Picture } from "vite-imagetools";

View File

@@ -1,17 +0,0 @@
export function tryOneOf<const T>(
value: T extends LiteralUnionLike<T> ? unknown : never,
consts: readonly T[],
) {
if (consts.includes(value)) return value;
return undefined;
}
export function sample<T>(arr: T[], n: number = arr.length): T[] {
if (n > arr.length) return sample(arr, arr.length);
const copy = [...arr];
for (let i = 0; i < n; i++) {
const j = i + Math.floor(Math.random() * (copy.length - i));
[copy[i], copy[j]] = [copy[j] as T, copy[i] as T];
}
return copy.slice(0, n);
}

View File

@@ -1,9 +1,9 @@
import { sampleMany } from "@cannorin/utils/array";
import { type RequestEvent, text } from "@sveltejs/kit";
import { RateLimiter } from "sveltekit-rate-limiter/server";
import { dev } from "$app/environment";
import { MISSKEY_API_KEY } from "$env/static/private";
import { sample } from "$lib";
import type { InviteListResponse } from "misskey-js/entities.js";
const limiter = new RateLimiter({
@@ -31,7 +31,7 @@ export async function GET(event: RequestEvent) {
},
);
const json = await res.json();
const invite = sample(json as InviteListResponse).find(
const invite = sampleMany(json as InviteListResponse).find(
(x) => !x.createdBy && !x.usedAt,
);
if (invite) return text(invite.code);

View File

@@ -8,7 +8,6 @@ import {
right,
worlds,
} from "@cannorin/kripke";
import type { SVGAttributes } from "svelte/elements";
import {
type Radian,
type Vector,
@@ -17,7 +16,8 @@ import {
rotate,
sub,
theta,
} from "../lib/vector";
} from "@cannorin/utils/vector";
import type { SVGAttributes } from "svelte/elements";
export interface FrameInputProps extends SVGAttributes<SVGElement> {
frame?: Frame | undefined;

View File

@@ -1,54 +0,0 @@
export class MultiSet<T> extends Map<T, number> {
constructor(iterable?: Iterable<readonly [T, number]>) {
super();
if (iterable) {
for (const [item, count] of iterable) {
this.add(item, count);
}
}
}
/**
* Adds the specified item to the multiset.
* If the item already exists, its count is incremented.
*
* @param item The element to add.
* @param count The number of times to add the element (default is 1).
* @returns The current instance for chaining.
*/
add(item: T, count = 1): this {
const currentCount = this.get(item) ?? 0;
this.set(item, currentCount + count);
return this;
}
/**
* Removes one or more instances of the specified item.
*
* @param item The element to remove.
* @param count The number of times to remove the element (default is 1).
* @returns True if the element was present, false otherwise.
*/
remove(item: T, count = 1): boolean {
const currentCount = this.get(item);
if (currentCount === undefined) {
return false;
}
if (currentCount <= count) {
this.delete(item);
} else {
this.set(item, currentCount - count);
}
return true;
}
/**
* Retrieves the count of the specified item.
*
* @param item The element whose count is to be retrieved.
* @returns The number of occurrences of the element.
*/
count(item: T): number {
return this.get(item) ?? 0;
}
}

View File

@@ -1,6 +1,6 @@
import { MultiSet } from "@cannorin/utils/multiset";
import { persisted } from "svelte-persisted-store";
import type { Move } from "../components/game.svelte";
import { MultiSet } from "./multiset";
import { date } from "./system";
export type Daily = {

View File

@@ -1,28 +0,0 @@
export type Vector = {
x: number;
y: number;
};
export type Radian = number;
export const degree = (value: number) => ((value / 180) * Math.PI) as Radian;
export const sub = (v1: Vector, v2: Vector) =>
({
x: v1.x - v2.x,
y: v1.y - v2.y,
}) as Vector;
export const add = (v1: Vector, v2: Vector) =>
({
x: v1.x + v2.x,
y: v1.y + v2.y,
}) as Vector;
export const theta = ({ x, y }: Vector) => Math.atan2(y, x) as Radian;
export const rotate = ({ x, y }: Vector, rad: Radian) =>
({
x: x * Math.cos(rad) - y * Math.sin(rad),
y: x * Math.sin(rad) + y * Math.cos(rad),
}) as Vector;

View File

@@ -1,7 +1,8 @@
<script lang="ts">
import { Button } from "$lib/components/ui/button";
import * as Dialog from "$lib/components/ui/dialog";
import { type Formula, isomorphic, validWorlds } from "@cannorin/kripke";
import { type Formula, isomorphic } from "@cannorin/kripke";
import { validWorlds } from "@cannorin/kripke/sat";
import LuRotateCw from "lucide-svelte/icons/rotate-cw";
import LuX from "lucide-svelte/icons/x";