feat: add inline-schema/csv-loader/rollup for tsup/vite

This commit is contained in:
hypercross 2026-04-04 16:44:03 +08:00
parent d9a91ae8be
commit 08cac3965e
4 changed files with 148 additions and 1 deletions

View File

@ -1,6 +1,6 @@
# inline-schema/csv-loader # 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 ## Installation
@ -24,6 +24,8 @@ Alice,30,true,[90; 85; 95]
Bob,25,false,[75; 80; 70] Bob,25,false,[75; 80; 70]
``` ```
## rspack/webpack
### rspack.config.js ### rspack.config.js
```javascript ```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 ### Generated TypeScript Types
`emitTypes: true`loader 会自动生成 `.d.ts` 类型定义文件: `emitTypes: true`loader 会自动生成 `.d.ts` 类型定义文件:
@ -91,6 +134,8 @@ import data from './data.csv';
| `emitTypes` | boolean | `true` | Generate TypeScript declaration file (.d.ts) | | `emitTypes` | boolean | `true` | Generate TypeScript declaration file (.d.ts) |
| `typesOutputDir` | string | `''` | Output directory for generated type files (relative to output path) | | `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) | | `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 ## Schema Syntax

View File

@ -14,6 +14,11 @@
"types": "./dist/csv-loader/loader.d.ts", "types": "./dist/csv-loader/loader.d.ts",
"import": "./dist/csv-loader/loader.mjs", "import": "./dist/csv-loader/loader.mjs",
"require": "./dist/csv-loader/loader.js" "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": { "scripts": {

89
src/csv-loader/rollup.ts Normal file
View File

@ -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<RegExp | string>;
/** Exclude pattern for CSV files */
exclude?: RegExp | string | Array<RegExp | 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);
});
}
/**
* 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;

View File

@ -16,4 +16,12 @@ export default defineConfig([
external: ['@rspack/core', 'csv-parse'], external: ['@rspack/core', 'csv-parse'],
clean: false, clean: false,
}, },
{
entry: ['src/csv-loader/rollup.ts'],
format: ['cjs', 'esm'],
dts: true,
outDir: 'dist/csv-loader',
external: ['rollup', 'csv-parse'],
clean: false,
},
]); ]);