hypercross 6da2815301 refactor: decouple table loading from lookup generation
Extract `loadReferenceTableData` to separate the raw file loading
logic from the primary key lookup construction. This prevents
unnecessary Map creation during reverse reference resolution.
2026-08-06 10:42:10 +08:00
2026-04-02 21:03:57 +08:00

typed-csv

A TypeScript library for typed CSV data with inline schema validation using a TypeScript-like syntax with ; instead of ,.

Installation

npm install typed-csv

Usage

Basic Example

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

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

// 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

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:

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:

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

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.
// rspack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.schema\.csv$/,
        use: 'typed-csv/csv-loader',
      },
    ],
  },
};

License

ISC

S
Description
helper for type shorthands, for csv parsing
Readme
739 KiB
Languages
TypeScript 100%