From 08cac3965e823e2e1882154c103d571e72714fb7 Mon Sep 17 00:00:00 2001 From: hypercross Date: Sat, 4 Apr 2026 16:44:03 +0800 Subject: [PATCH] feat: add inline-schema/csv-loader/rollup for tsup/vite --- csv-loader.md | 47 ++++++++++++++++++++- package.json | 5 +++ src/csv-loader/rollup.ts | 89 ++++++++++++++++++++++++++++++++++++++++ tsup.config.ts | 8 ++++ 4 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 src/csv-loader/rollup.ts diff --git a/csv-loader.md b/csv-loader.md index 2cf6295..adf3e98 100644 --- a/csv-loader.md +++ b/csv-loader.md @@ -1,6 +1,6 @@ # inline-schema/csv-loader -A rspack loader for CSV files that uses inline-schema for type validation. +A rspack/rollup loader for CSV files that uses inline-schema for type validation. ## Installation @@ -24,6 +24,8 @@ Alice,30,true,[90; 85; 95] Bob,25,false,[75; 80; 70] ``` +## rspack/webpack + ### rspack.config.js ```javascript @@ -52,6 +54,47 @@ module.exports = { }; ``` +## Vite + +### vite.config.ts + +```typescript +import { defineConfig } from 'vite'; +import { csvLoader } from 'inline-schema/csv-loader/rollup'; + +export default defineConfig({ + plugins: [ + csvLoader({ + delimiter: ',', + quote: '"', + escape: '\\', + bom: true, + comment: '#', + trim: true, + // emitTypes: false, + // typesOutputDir: 'types', + // writeToDisk: true, + }), + ], +}); +``` + +## Tsup + +### tsup.config.ts + +```typescript +import { defineConfig } from 'tsup'; +import { csvLoader } from 'inline-schema/csv-loader/rollup'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['cjs', 'esm'], + dts: true, + plugins: [csvLoader()], +}); +``` + ### Generated TypeScript Types 当 `emitTypes: true` 时,loader 会自动生成 `.d.ts` 类型定义文件: @@ -91,6 +134,8 @@ import data from './data.csv'; | `emitTypes` | boolean | `true` | Generate TypeScript declaration file (.d.ts) | | `typesOutputDir` | string | `''` | Output directory for generated type files (relative to output path) | | `writeToDisk` | boolean | `false` | Write .d.ts files directly to disk (useful for dev server) | +| `include` | RegExp \| string \| Array | `/\.csv$/` | Include pattern for CSV files (Rollup only) | +| `exclude` | RegExp \| string \| Array | - | Exclude pattern for CSV files (Rollup only) | ## Schema Syntax diff --git a/package.json b/package.json index 40e2571..1be56bf 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,11 @@ "types": "./dist/csv-loader/loader.d.ts", "import": "./dist/csv-loader/loader.mjs", "require": "./dist/csv-loader/loader.js" + }, + "./csv-loader/rollup": { + "types": "./dist/csv-loader/rollup.d.ts", + "import": "./dist/csv-loader/rollup.mjs", + "require": "./dist/csv-loader/rollup.js" } }, "scripts": { diff --git a/src/csv-loader/rollup.ts b/src/csv-loader/rollup.ts new file mode 100644 index 0000000..b16c234 --- /dev/null +++ b/src/csv-loader/rollup.ts @@ -0,0 +1,89 @@ +import type { Plugin } from 'rollup'; +import type { CsvLoaderOptions } from './loader.js'; +import { csvToModule } from './loader.js'; +import * as path from 'path'; +import * as fs from 'fs'; + +export interface CsvRollupOptions extends CsvLoaderOptions { + /** Include pattern for CSV files (default: /\.csv$/) */ + include?: RegExp | string | Array; + /** Exclude pattern for CSV files */ + exclude?: RegExp | string | Array; +} + +function matchesPattern( + id: string, + pattern: RegExp | string | Array | 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); + }); +} + +/** + * Rollup plugin for loading CSV files with inline-schema validation. + * Works with both Vite and Tsup (esbuild). + */ +export function csvLoader(options: CsvRollupOptions = {}): Plugin { + const { + include = /\.csv$/, + exclude, + emitTypes = true, + typesOutputDir = '', + writeToDisk = false, + ...parseOptions + } = options; + + return { + name: 'inline-schema-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; + + const result = csvToModule(code, { + ...parseOptions, + emitTypes, + }); + + // 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; diff --git a/tsup.config.ts b/tsup.config.ts index 874d6fe..5fb6041 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -16,4 +16,12 @@ export default defineConfig([ external: ['@rspack/core', 'csv-parse'], clean: false, }, + { + entry: ['src/csv-loader/rollup.ts'], + format: ['cjs', 'esm'], + dts: true, + outDir: 'dist/csv-loader', + external: ['rollup', 'csv-parse'], + clean: false, + }, ]);