Implement a reverse lookup cache to avoid re-filtering the entire referenced table for every row during reverse reference resolution. This improves performance from O(N*M) to O(N+M) where N is the number of rows in the current table and M is the number of rows in the referenced table. Also update documentation to reflect the new union resolution behavior and migration notes for version 2.0.0.
191 lines
6.1 KiB
Markdown
191 lines
6.1 KiB
Markdown
# typed-csv
|
|
|
|
A TypeScript library for typed CSV data with inline schema validation using a TypeScript-like syntax with `;` instead of `,`.
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
npm install typed-csv
|
|
```
|
|
|
|
## Usage
|
|
|
|
### Basic Example
|
|
|
|
```typescript
|
|
import { defineSchema } from 'typed-csv';
|
|
|
|
// Define a schema
|
|
const stringSchema = defineSchema('string');
|
|
const numberSchema = defineSchema('number');
|
|
const booleanSchema = defineSchema('boolean');
|
|
|
|
// Parse values
|
|
const name = stringSchema.parse('hello'); // "hello"
|
|
const age = numberSchema.parse('42'); // 42
|
|
const active = booleanSchema.parse('true'); // true
|
|
|
|
// Validate parsed values
|
|
stringSchema.validator(name); // true
|
|
numberSchema.validator(name); // false
|
|
```
|
|
|
|
### Tuples
|
|
|
|
```typescript
|
|
const tupleSchema = defineSchema('[string; number; boolean]');
|
|
|
|
const value1 = tupleSchema.parse('[hello; 42; true]');
|
|
// ["hello", 42, true]
|
|
|
|
tupleSchema.validator(value1); // true
|
|
tupleSchema.validator(['a', 'b', true]); // false (second element should be number)
|
|
```
|
|
|
|
### Arrays
|
|
|
|
```typescript
|
|
// Array syntax: Type[]
|
|
const stringArray = defineSchema('string[]');
|
|
const numberArray = defineSchema('number[]');
|
|
|
|
const names = stringArray.parse('[alice; bob; charlie]');
|
|
// ["alice", "bob", "charlie"]
|
|
|
|
const numbers = numberArray.parse('[1; 2; 3; 4; 5]');
|
|
// [1, 2, 3, 4, 5]
|
|
```
|
|
|
|
### Array of Tuples
|
|
|
|
```typescript
|
|
const schema = defineSchema('[string; number][]');
|
|
|
|
const data = schema.parse('[[a; 1]; [b; 2]; [c; 3]]');
|
|
// [["a", 1], ["b", 2], ["c", 3]]
|
|
```
|
|
|
|
### Escaping Special Characters
|
|
|
|
Use `\` to escape special characters `;`, `[`, `]`, and `\` in string values:
|
|
|
|
```typescript
|
|
const schema = defineSchema('string');
|
|
|
|
const value1 = schema.parse('hello\\;world'); // "hello;world"
|
|
const value2 = schema.parse('hello\\[world'); // "hello[world"
|
|
const value3 = schema.parse('hello\\\\world'); // "hello\\world"
|
|
|
|
// In tuples
|
|
const tupleSchema = defineSchema('[string; string]');
|
|
const tuple = tupleSchema.parse('hello\\;world; test');
|
|
// ["hello;world", "test"]
|
|
```
|
|
|
|
### String Identifiers
|
|
|
|
Any identifier (including hyphens) is treated as a string schema:
|
|
|
|
```typescript
|
|
const schema = defineSchema('word-smith');
|
|
const value = schema.parse('word-smith');
|
|
// "word-smith"
|
|
```
|
|
|
|
## API
|
|
|
|
### `defineSchema(schemaString: string): ParsedSchema`
|
|
|
|
Parses a schema string and returns an object with:
|
|
- `schema`: The parsed schema AST
|
|
- `validator`: A function to validate values against the schema
|
|
- `parse`: A function to parse value strings
|
|
|
|
### `parseSchema(schemaString: string): Schema`
|
|
|
|
Parses a schema string and returns the schema AST.
|
|
|
|
### `parseValue(schema: Schema, valueString: string): unknown`
|
|
|
|
Parses a value string according to the given schema.
|
|
|
|
### `createValidator(schema: Schema): (value: unknown) => boolean`
|
|
|
|
Creates a validation function for the given schema.
|
|
|
|
### `schemaToTypeString(schema: Schema): string`
|
|
|
|
Converts a schema AST back to a human-readable type string.
|
|
|
|
### `ParseError`
|
|
|
|
Error class thrown for invalid schema syntax.
|
|
|
|
### Types
|
|
|
|
The following TypeScript types are exported:
|
|
|
|
- `Schema` — union of all schema AST node types
|
|
- `ParsedSchema` — the return type of `defineSchema()`
|
|
- `PrimitiveSchema`, `TupleSchema`, `ArraySchema` — AST node types
|
|
- `ReferenceSchema`, `ReverseReferenceSchema` — reference AST node types
|
|
- `StringLiteralSchema`, `UnionSchema` — literal and union AST node types
|
|
|
|
## Schema Syntax
|
|
|
|
| Type | Schema | Example Value |
|
|
|------|--------|---------------|
|
|
| String | `string` or `identifier` | `hello` |
|
|
| Int | `int` | `42` |
|
|
| Float | `float` | `3.14` |
|
|
| Number | `number` | `42` or `3.14` |
|
|
|
|
> **Note:** `int`, `float`, and `number` all collapse to the `number` type in generated TypeScript declarations (`schemaToTypeString`). The distinction is preserved at parse time — `int` rejects non-integer values while `float`/`number` accept them.
|
|
| Boolean | `boolean` | `true` or `false` |
|
|
| Tuple | `[Type1; Type2; ...]` | `[hello; 42; true]` |
|
|
| Array | `Type[]` | `[1; 2; 3]` |
|
|
| Array of Tuples | `[Type1; Type2][]` | `[[a; 1]; [b; 2]]` |
|
|
| Union | `Type1 \| Type2` | `hello` or `42` (reference members tried first) |
|
|
| String Literal | `'on' \| 'off'` or `"red"` | `on` or `off` |
|
|
| Reference | `@tablename` or `@tablename[]` | (resolved at CSV load time) |
|
|
| Reverse Reference | `~tablename(fk)` | (resolved at CSV load time) |
|
|
|
|
## Notes
|
|
|
|
- Semicolons `;` are used as separators instead of commas `,`
|
|
- Tuple and array values **must** be wrapped in brackets `[]` (e.g. `[a; b]`)
|
|
- `[single]` is a 1-tuple, not an array — use `Type[]` for arrays
|
|
- In a union, **reference members are tried before non-reference members** (e.g. `@users | string` resolves `1` to the user object, falling back to a plain string when the reference doesn't match)
|
|
- Special characters can be escaped with backslash: `\;`, `\[`, `\]`, `\\`
|
|
- Empty arrays/tuples are not allowed
|
|
- In CSV schema rows, double-quoted string literals like `"active" | "inactive"` are handled automatically by the loader; avoid commas inside string literals (use single-quoted literals like `'a,b'` for those)
|
|
- For CSV loading with reference resolution, see [csv-loader.md](./csv-loader.md)
|
|
|
|
## Migration from 1.x
|
|
|
|
Version 2.0.0 introduces breaking changes to the schema DSL:
|
|
|
|
1. **Composite values must be fully bracketed.** Tuple and array values now always require `[]` — `[a; 1]; [b; 2]` is no longer accepted; write `[[a; 1]; [b; 2]]`.
|
|
2. **The `[Type][]` array form is removed.** Use `Type[]` (e.g. `[string; number][]` instead of `[[string; number]][]`).
|
|
3. **`[single]` is now a 1-tuple, not an array.** Use `Type[]` for single-element arrays.
|
|
4. **Union resolution prefers reference members.** In a union containing references, reference members are tried before non-reference members regardless of author order (see the notes above).
|
|
5. **Schema cells may be fully quoted.** Double-quoted string literals like `"active" | "inactive"` in a CSV schema row are handled automatically by the loader.
|
|
|
|
```javascript
|
|
// rspack.config.js
|
|
module.exports = {
|
|
module: {
|
|
rules: [
|
|
{
|
|
test: /\.schema\.csv$/,
|
|
use: 'typed-csv/csv-loader',
|
|
},
|
|
],
|
|
},
|
|
};
|
|
```
|
|
|
|
## License
|
|
|
|
ISC
|