@kniddo/types
v0.1.2
Published
Shared type definitions for Kniddo projects
Downloads
35
Readme
@kniddo/types
Shared type definitions for Kniddo projects. Uses JSON Schema as the single source of truth with generators for both TypeScript interfaces and Dart base classes.
Architecture
schemas/*.schema.json (source of truth)
│
├──► ts-generator ──► src/generated/models/*.ts (TypeScript interfaces)
│ │
│ └──► tsc ──► dist/ (compiled JS + .d.ts)
│
└──► dart-generator ──► kniddo_flutter/lib/models/generated/*_base.g.dart
(Dart abstract base classes)Dart Generation Strategy
"Generate base, extend manually" — the generator produces _FooBase abstract classes with fields, fromJSON, encodeBase, and props. The developer writes class Foo extends _FooBase in a separate file, adding behavior, factory constructors, and custom logic. Generated files use Dart's part/part of mechanism so they share the host file's library scope.
Project Structure
kniddo_types/
├── schemas/
│ ├── enums/ # Enum schemas (5 files)
│ └── models/ # Model schemas (22 files)
├── generators/
│ ├── generate.ts # CLI entry point (--ts, --dart, --all, --validate)
│ ├── schema-loader.ts # Load schemas, resolve $ref, topological sort
│ ├── ts-generator.ts # JSON Schema → TypeScript interfaces
│ ├── dart-generator.ts # JSON Schema → Dart base classes
│ └── type-mapping.ts # Shared type resolution utilities
├── src/
│ ├── generated/ # Auto-generated TypeScript (do not edit)
│ │ ├── models/ # Generated interfaces
│ │ └── index.ts # Barrel export
│ ├── constants/ # Hand-written constants (db collections, needle sizes)
│ ├── api/ # Hand-written API request/response types
│ └── index.ts # Main package export
├── scripts/
│ └── validate-dart.ts # Dart ↔ TypeScript type shape validator
├── package.json
└── tsconfig.jsonScripts
npm run generate # Generate TypeScript + Dart
npm run generate:ts # TypeScript only
npm run generate:dart # Dart only
npm run generate:validate # Validate schemas with ajv
npm run build # Generate TypeScript + compile with tsc
npm run clean # Remove dist/ and src/generated/
npm run validate-dart # Validate Dart ↔ TS structural compatibilityConsuming Projects
| Project | Integration |
|---------|------------|
| kniddo_web | "@kniddo/types": "file:../kniddo_types" in package.json + Vite alias |
| kniddo_firebase | "@kniddo/types": "file:../../kniddo_types" in functions/package.json |
| kniddo_flutter | Dart base classes generated directly into lib/models/generated/ |
Schema Format
Standard JSON Schema (draft 2020-12) with custom extensions:
Custom Extensions
| Key | Purpose | Example |
|-----|---------|---------|
| x-kniddo-format | Semantic type hint | "timestamp" → Dart DateTime, "duration-seconds" → Dart Duration |
| x-kniddo-extends | Schema inheritance | { "$ref": "./yarn-info.schema.json" } |
| x-kniddo-dart-type | Override Dart type | "int" to force int instead of num |
| x-kniddo-dart-class | Override Dart class name | "Measurement" on MeasurementSystem |
| x-kniddo-dart-field | Override Dart/Firestore field key | "quanties" (preserves Firestore typo) |
| x-kniddo-dart-exclude | Skip Dart generation | true on CounterColourSetID |
| x-kniddo-ts-extra-type | Add union member in TS | "string" → PatternStatus \| string |
Type Mapping
| JSON Schema | TypeScript | Dart |
|---|---|---|
| "type": "string" | string | String |
| "type": "number" | number | num |
| "type": "boolean" | boolean | bool |
| "type": "array", "items": X | X[] | List<X> |
| "type": "object", "additionalProperties": V | Record<string, V> | Map<String, V> |
| "enum": [...] | 'a' \| 'b' \| ... | enum { a, b, ... } |
| x-kniddo-format: "timestamp" | number | DateTime |
| x-kniddo-format: "duration-seconds" | number | Duration |
Example Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "User",
"type": "object",
"properties": {
"id": { "type": "string" },
"displayName": { "type": "string" },
"email": { "type": "string" },
"role": { "$ref": "../enums/user-role.schema.json" },
"updatedTime": { "type": "number", "x-kniddo-format": "timestamp" },
"createdTime": { "type": "number", "x-kniddo-format": "timestamp" }
},
"required": ["id", "displayName", "email", "role", "updatedTime", "createdTime"]
}What Stays Hand-Written
| Item | Why |
|---|---|
| src/constants/db-collections.ts | Runtime collection names, not data shape |
| src/constants/needle-sizes.ts | Runtime lookup data with helper functions |
| src/api/pattern-api.ts | Small API surface, low ROI for schema |
| Flutter model subclasses | Custom behavior, factory constructors, legacy migration |
| CounterColourSetID in Dart | Complex display name mapping |
