@typest/core
v1.0.4
Published
Typed asset paths – core scanner & code generator
Maintainers
Readme
@typest/core
Scan asset folders, detect file types, and generate typed JavaScript & TypeScript code.
Installation
npm install @typest/coreWhat it does
scanAssets– walks directories and returns every file with its public URL, detected type, and a unique key.generateRuntimeModule– produces a browser‑ready JavaScript file that exportsimagePath,videoPath, etc., only for asset types that actually exist.generateDeclarations– builds a.d.tsfile with exact literal types so editors can provide perfect autocomplete.watchAssets– watches asset folders and fires a callback on every change.
Framework plugins like @typest/vite are thin wrappers around these four functions.
Quick example
import {
scanAssets,
generateRuntimeModule,
generateDeclarations,
} from "@typest/core";
const entries = await scanAssets([{ dir: "public" }]);
const runtimeJS = generateRuntimeModule(entries); // serve as virtual module
const typesDts = generateDeclarations(entries); // write to disk for TypeScriptEach entry: { key: "logo.png", url: "/logo.png", type: "image", ext: "png" }
Scan options
import { scanAssets } from "@typest/core";
const entries = await scanAssets(
[
{
dir: "public/assets",
include: ["**/*"],
exclude: ["**/*.psd"],
basePath: "/assets",
typeMap: { glb: "raw" }, // override extension → type mapping
},
],
{
keyStrategy: "filename", // default – keys are just the filename
globalBasePath: "",
customTypes: { glb: "raw" }, // global type overrides
},
);AssetSource
| Option | Type | Default | Description |
| ---------- | --------------------------- | ----------- | -------------------------------------------------------------- |
| dir | string | required | Path to the asset folder (relative to project root). |
| basePath | string | undefined | Public URL prefix (e.g. "/images"). |
| include | string[] | ["**/*"] | Glob patterns to include. |
| exclude | string[] | [] | Glob patterns to exclude. |
| typeMap | Record<string, AssetType> | undefined | Override the default extension → type mapping for this source. |
ScanOptions
| Option | Type | Default | Description |
| ---------------- | ---------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| keyStrategy | "filename" or "relative" | "filename" | How keys are built. "filename" uses only the filename (logo.png); "relative" includes the subpath (images/logo.png). |
| customTypes | Record<string, AssetType> | undefined | Additional extension → type mappings merged with the defaults. |
| globalBasePath | string | "" | Prepend this to every generated URL (useful for CDN). |
Watching
import { watchAssets } from "@typest/core";
const watcher = watchAssets([{ dir: "public", basePath: "" }], (entries) => {
// Re‑generate your runtime module and declarations here
console.log("Assets changed:", entries.length);
});
// Later:
watcher.close();Default type map
| Extension | Type |
| ---------------------------------------------------------------- | --------- |
| .png, .jpg, .jpeg, .webp, .gif, .svg, .ico, .bmp | image |
| .mp4, .webm, .avi, .mov, .mkv | video |
| .mp3, .wav, .ogg, .flac, .aac | audio |
| .woff, .woff2, .ttf, .eot, .otf | font |
| .txt, .csv, .json, .xml, .yaml, .yml | raw |
| everything else | generic |
You can override these per‑source or globally via typeMap / customTypes.
Building your own plugin
If you're creating a framework integration (e.g., for Webpack or a new bundler), use the core like this:
import {
scanAssets,
generateRuntimeModule,
generateDeclarations,
} from "@typest/core";
// 1. Scan
const entries = await scanAssets([{ dir: "public" }]);
// 2. Serve the runtime module as a virtual module
const runtimeCode = generateRuntimeModule(entries);
// 3. Write the declarations somewhere TypeScript can find them
const dts = generateDeclarations(entries);
await fs.writeFile("src/assets.d.ts", dts);For a complete real‑world example, see the source of @typest/vite.
API
scanAssets(sources: AssetSource[], options?: ScanOptions): Promise<AssetEntry[]>
generateRuntimeModule(entries: AssetEntry[]): string
generateDeclarations(entries: AssetEntry[]): string
watchAssets(
sources: AssetSource[],
callback: (entries: AssetEntry[]) => void,
options?: ScanOptions,
watchOptions?: chokidar.WatchOptions
): FSWatcher- Keys are filenames by default – clean, short, predictable.
- Only existing asset types are emitted – no empty objects or unused functions.
- All paths are normalised – forward slashes, leading slash prepended automatically.
