feat: esbuild csv-loader support
This commit is contained in:
parent
4eb6a17e9f
commit
77ee96d70c
|
|
@ -0,0 +1,118 @@
|
||||||
|
import type { CsvLoaderOptions } from './loader.js';
|
||||||
|
import { csvToModule } from './loader.js';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import type { Plugin, OnLoadArgs, OnLoadResult } from 'esbuild';
|
||||||
|
|
||||||
|
export interface CsvEsbuildOptions 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>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchesFilter(
|
||||||
|
path: string,
|
||||||
|
filter: RegExp | undefined
|
||||||
|
): boolean {
|
||||||
|
if (!filter) return true;
|
||||||
|
return filter.test(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Esbuild plugin for loading CSV files with inline-schema validation.
|
||||||
|
*/
|
||||||
|
export function csvLoader(options: CsvEsbuildOptions = {}): Plugin {
|
||||||
|
const {
|
||||||
|
include = /\.csv$/,
|
||||||
|
exclude,
|
||||||
|
emitTypes = true,
|
||||||
|
typesOutputDir = '',
|
||||||
|
writeToDisk = false,
|
||||||
|
...parseOptions
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
// Convert include/exclude to RegExp for esbuild filter
|
||||||
|
const includeFilter = includeToRegExp(include);
|
||||||
|
const excludeFilter = exclude ? includeToRegExp(exclude) : undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: 'inline-schema-csv',
|
||||||
|
|
||||||
|
setup(build) {
|
||||||
|
build.onLoad({ filter: includeFilter }, async (args: OnLoadArgs) => {
|
||||||
|
// Check exclude pattern
|
||||||
|
if (excludeFilter && !matchesFilter(args.path, excludeFilter)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only process .csv files
|
||||||
|
if (!args.path.endsWith('.csv')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the file content
|
||||||
|
let content: string;
|
||||||
|
try {
|
||||||
|
content = await fs.promises.readFile(args.path, 'utf-8');
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
errors: [{ text: `Failed to read file: ${args.path}` }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infer resource name from filename
|
||||||
|
const fileName = path.basename(args.path, '.csv').split('.')[0];
|
||||||
|
const resourceName = fileName
|
||||||
|
.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : '')
|
||||||
|
.replace(/^(.)/, (_, char) => char.toUpperCase());
|
||||||
|
|
||||||
|
const result = csvToModule(content, {
|
||||||
|
...parseOptions,
|
||||||
|
emitTypes,
|
||||||
|
resourceName,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Emit type definition file if enabled
|
||||||
|
if (emitTypes && result.dts) {
|
||||||
|
const dtsPath = typesOutputDir
|
||||||
|
? path.join(typesOutputDir, path.basename(args.path) + '.d.ts')
|
||||||
|
: args.path + '.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);
|
||||||
|
}
|
||||||
|
// Note: esbuild doesn't have a direct emitFile API like Rollup
|
||||||
|
// For type generation with writeToDisk: false, you'd need to
|
||||||
|
// use a separate type generation step or plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
const onLoadResult: OnLoadResult = {
|
||||||
|
contents: result.js,
|
||||||
|
loader: 'js',
|
||||||
|
};
|
||||||
|
|
||||||
|
return onLoadResult;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function includeToRegExp(include: RegExp | string | Array<RegExp | string>): RegExp {
|
||||||
|
if (include instanceof RegExp) {
|
||||||
|
return include;
|
||||||
|
}
|
||||||
|
if (Array.isArray(include)) {
|
||||||
|
// Use the first pattern or create a combined pattern
|
||||||
|
const first = include[0];
|
||||||
|
return first instanceof RegExp ? first : new RegExp(first);
|
||||||
|
}
|
||||||
|
return new RegExp(include);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default csvLoader;
|
||||||
Loading…
Reference in New Issue