Compare commits

...
3 Commits
Author SHA1 Message Date
TrèsAbhi 44711a58c7 feat: discrimination 2026-03-20 20:40:45 -05:00
TrèsAbhi e7337145d2 feat: some caching 2026-03-20 20:38:04 -05:00
TrèsAbhi c116b40dfc feat: some more docs 2026-03-20 19:58:56 -05:00
7 changed files with 55 additions and 37 deletions

No files matched your search

@@ -59,6 +59,8 @@ for (const line of bodyOriginal.split("\n")) {
flex-direction: column;
gap: var(--space-4);
width: 100%;
padding-top: var(--space-4);
padding-bottom: var(--space-3);
}
@@ -1,22 +1,12 @@
---
import { resolve } from "path";
import { readFile } from "fs/promises";
import { Link } from "./Link";
import { api } from "../core/api/dynamic";
import HighlightedCodeBlock from "./HighlightedCodeBlock.astro";
import { Text } from "./Text";
import { ArrowBottomRightIcon } from "@radix-ui/react-icons";
import { Code } from "./Code";
import { resolve } from "path";
import {
createProgram,
forEachChild,
isArrayTypeNode,
isEnumDeclaration,
isExpressionWithTypeArguments,
isInterfaceDeclaration,
isMethodSignature,
isPropertySignature,
isTypeAliasDeclaration,
isTypeNode,
isTypeReferenceNode,
type InterfaceDeclaration,
@@ -24,12 +14,19 @@ import {
type Symbol,
type TypeNode,
} from "typescript";
import { api } from "../core/api/dynamic";
import { Code } from "./Code";
import HighlightedCodeBlock from "./HighlightedCodeBlock.astro";
import { Link } from "./Link";
import { Text } from "./Text";
interface Props {
value: string;
locale: string;
}
const DEFAULT_EXPANDED = 8;
const { value, locale } = Astro.props;
const strings = await api.strings(locale);
@@ -192,7 +189,10 @@ content = content.trim();
<ArrowBottomRightIcon />
</div>
<div class="types">
<div
class="types"
data-expanded={content.split("\n").length <= DEFAULT_EXPANDED}
>
<HighlightedCodeBlock {lang} content={content} />
<div class="overlay">
+30 -19
View File
@@ -11,25 +11,8 @@ import type { TankList } from "../../protos/tank_list";
import type { Tanks } from "../../protos/tanks";
export abstract class AbstractAPI {
private _tankListCache: TankList | undefined;
protected abstract _tankList(): Promise<TankList>;
async tankList() {
if (this._tankListCache === undefined) {
this._tankListCache = await this._tankList();
}
return this._tankListCache;
}
private _tankCache: Record<string, Tank> = {};
protected abstract _tank(id: string): Promise<Tank>;
async tank(id: string) {
if (this._tankCache[id] === undefined) {
this._tankCache[id] = await this._tank(id);
}
return this._tankCache[id];
}
abstract tankList(): Promise<TankList>;
abstract tank(id: string): Promise<Tank>;
private _tanksCache: Tanks | undefined;
protected abstract _tanks(): Promise<Tanks>;
@@ -181,3 +164,31 @@ export abstract class AbstractAPI {
return this._popularTanksCache;
}
}
export function Cache<Arguments extends unknown[]>(
discriminator: (...args: Arguments) => string = () => "",
) {
const cache = new WeakMap<object, Map<string, unknown>>();
return function (
_target: unknown,
_propertyKey: string,
descriptor: PropertyDescriptor,
) {
const original = descriptor.value;
descriptor.value = async function (...args: Arguments) {
const key = discriminator(...args);
const thisCache = cache.get(this) ?? new Map<string, unknown>();
if (!cache.has(this)) cache.set(this, thisCache);
if (thisCache.has(key)) return thisCache.get(key);
const result = await original.apply(this, args);
thisCache.set(key, result);
return result;
};
};
}
+6 -4
View File
@@ -15,7 +15,7 @@ import type { PopularTanks } from "../../protos/popular_tanks";
import type { Tank } from "../../protos/tank";
import type { TankListEntry } from "../../protos/tank_list";
import type { Tanks } from "../../protos/tanks";
import { AbstractAPI } from "./abstract";
import { AbstractAPI, Cache } from "./abstract";
if (typeof window !== "undefined") {
throw new Error("ServerAPI is being evaluated in the browser");
@@ -133,7 +133,8 @@ export class ServerAPI extends AbstractAPI {
return strings;
}
protected async _tankList() {
@Cache()
async tankList() {
const group = this.metadata.group("TankEntity");
const list: TankListEntry[] = [];
const strings = await this.groupedGameStrings("en", "TankEntity", true);
@@ -167,7 +168,8 @@ export class ServerAPI extends AbstractAPI {
return data;
}
protected async _tank(id: string) {
@Cache<[string]>((id) => id)
async tank(id: string) {
const tankList = await this.tankList();
const tankListEntry = tankList.list.find((tank) => tank.id === id);
@@ -195,7 +197,7 @@ export class ServerAPI extends AbstractAPI {
protected async _avatarList() {
const avatars = await this.avatars();
const list = Object.keys(avatars.avatars);
const list = avatars.avatars.map((avatar) => avatar.name);
return { list };
}
@@ -2,7 +2,7 @@ import { api } from "../../../core/api/dynamic";
/**
* Identical to `avatars/[id].json`, but returns data on all avatars at once,
* mapped by `id`. Beware, the returned `JSON` is large.
* mapped by `id`.
*
* @type avatars.Avatars
*/
@@ -1,6 +1,8 @@
import { api } from "../../../core/api/dynamic";
/**
* Returns a list of all avatars ids.
*
* @type avatar_list.AvatarList
*/
export async function GET() {
+2 -1
View File
@@ -17,7 +17,8 @@
"paths": {
"@protos/*": ["./packages/closed/protos/*"]
},
"strictNullChecks": true
"strictNullChecks": true,
"experimentalDecorators": true
},
"exclude": ["node_modules/**/*", "dist"]
}