127 lines
3.3 KiB
TypeScript
127 lines
3.3 KiB
TypeScript
import * as path from "path";
|
|
import * as fs from "fs";
|
|
import { csvToModule } from "./module-gen";
|
|
import { CsvLoaderOptions } from "./types";
|
|
|
|
export interface CsvRollupOptions extends CsvLoaderOptions {
|
|
/** Include pattern for CSV files (default: /\.csv$/) */
|
|
include?: RegExp | string | Array<RegExp | string>;
|
|
/** Exclude pattern for CSV files */
|
|
exclude?: RegExp | string | Array<RegExp | string>;
|
|
/** Base directory for resolving referenced CSV files (default: directory of current file) */
|
|
refBaseDir?: string;
|
|
/** Primary key field name for referenced tables (default: 'id') */
|
|
defaultPrimaryKey?: string;
|
|
}
|
|
|
|
function matchesPattern(
|
|
id: string,
|
|
pattern: RegExp | string | Array<RegExp | string> | undefined,
|
|
): boolean {
|
|
if (!pattern) return true;
|
|
const patterns = Array.isArray(pattern) ? pattern : [pattern];
|
|
return patterns.some((p) => {
|
|
if (p instanceof RegExp) {
|
|
return p.test(id);
|
|
}
|
|
return id.includes(p);
|
|
});
|
|
}
|
|
|
|
interface TransformResult {
|
|
code: string;
|
|
map: null;
|
|
}
|
|
|
|
interface EmitFileOptions {
|
|
type: "asset";
|
|
fileName: string;
|
|
source: string;
|
|
}
|
|
|
|
interface PluginContext {
|
|
emitFile: (options: EmitFileOptions) => string;
|
|
}
|
|
|
|
interface RollupPlugin {
|
|
name: string;
|
|
transform: (
|
|
this: PluginContext,
|
|
code: string,
|
|
id: string,
|
|
) => TransformResult | null;
|
|
}
|
|
|
|
/**
|
|
* Rollup plugin for loading CSV files with typed-csv validation.
|
|
* Works with both Vite and Tsup (esbuild).
|
|
*/
|
|
export function csvLoader(options: CsvRollupOptions = {}): RollupPlugin {
|
|
const {
|
|
include = /\.csv$/,
|
|
exclude,
|
|
emitTypes = true,
|
|
typesOutputDir = "",
|
|
writeToDisk = false,
|
|
...parseOptions
|
|
} = options;
|
|
|
|
return {
|
|
name: "typed-csv",
|
|
|
|
transform(code: string, id: string) {
|
|
// Check if file matches the include/exclude patterns
|
|
if (!matchesPattern(id, include)) return null;
|
|
if (exclude && matchesPattern(id, exclude)) return null;
|
|
|
|
// Only process .csv files
|
|
if (!id.endsWith(".csv")) return null;
|
|
|
|
// Infer resource name from filename
|
|
const fileName = path.basename(id, ".csv").split(".")[0];
|
|
const resourceName = fileName
|
|
.replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ""))
|
|
.replace(/^(.)/, (_, char) => char.toUpperCase());
|
|
|
|
const result = csvToModule(code, {
|
|
...parseOptions,
|
|
emitTypes,
|
|
resourceName,
|
|
currentFilePath: id,
|
|
refBaseDir: options.refBaseDir,
|
|
defaultPrimaryKey: options.defaultPrimaryKey,
|
|
});
|
|
|
|
// Emit type definition file if enabled
|
|
if (emitTypes && result.dts) {
|
|
const dtsPath = typesOutputDir
|
|
? path.join(typesOutputDir, path.basename(id) + ".d.ts")
|
|
: id + ".d.ts";
|
|
|
|
if (writeToDisk) {
|
|
// Write directly to disk
|
|
const absolutePath = path.isAbsolute(dtsPath)
|
|
? dtsPath
|
|
: path.join(process.cwd(), dtsPath);
|
|
fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
|
|
fs.writeFileSync(absolutePath, result.dts);
|
|
} else {
|
|
// Emit to Rollup's virtual module system
|
|
this.emitFile({
|
|
type: "asset",
|
|
fileName: dtsPath,
|
|
source: result.dts,
|
|
});
|
|
}
|
|
}
|
|
|
|
return {
|
|
code: result.js,
|
|
map: null,
|
|
};
|
|
},
|
|
};
|
|
}
|
|
|
|
export default csvLoader;
|