CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-simpl-schema

A schema validation package that supports direct validation of MongoDB update modifier objects.

Pending
Overview
Eval results
Files

schema-introspection.mddocs/

Schema Introspection

Methods for examining schema structure, accessing field definitions, and navigating schema hierarchies.

Capabilities

Schema Definition Access

Methods to access and examine schema definitions.

/**
 * Gets the complete resolved schema definition
 * @returns Complete schema definition with all fields resolved
 */
schema(): ResolvedSchemaDefinition;

/**
 * Gets the definition for a specific field key
 * @param key - Field key to get definition for
 * @returns Field definition or null if key doesn't exist
 */
schema(key: string): StandardSchemaKeyDefinition | null;

/**
 * Gets all possible definitions for a field key (for union types)
 * @param key - Field key to get definitions for
 * @returns Array of field definitions
 */
schemas(key: string): StandardSchemaKeyDefinition[];

/**
 * Gets flattened schema with all subschemas merged
 * @returns Merged schema definition
 */
mergedSchema(): SchemaDefinition;

Usage Examples:

import SimpleSchema from "simpl-schema";

const userSchema = new SimpleSchema({
  name: String,
  email: {
    type: String,
    regEx: SimpleSchema.RegEx.Email,
    label: "Email Address"
  },
  role: SimpleSchema.oneOf(
    { type: String, allowedValues: ['admin', 'user'] },
    { type: Number, allowedValues: [1, 2] }
  )
});

// Get complete schema
const fullSchema = userSchema.schema();
console.log(Object.keys(fullSchema)); // ['name', 'email', 'role']

// Get specific field definition
const emailDef = userSchema.schema('email');
console.log(emailDef?.type); // StringConstructor
console.log(emailDef?.label); // "Email Address"

// Get definitions for union type field
const roleDefs = userSchema.schemas('role');
console.log(roleDefs.length); // 2 - one for string, one for number

// Get merged schema (flattened)
const merged = userSchema.mergedSchema();
console.log(merged);

Field Definition Evaluation

Get evaluated field definitions with function-based properties resolved.

/**
 * Gets evaluated definition for a field key with functions resolved
 * @param key - Field key to get definition for
 * @param propList - List of specific properties to evaluate
 * @param functionContext - Context object passed to property functions
 * @returns Evaluated field definition
 */
getDefinition(
  key: string, 
  propList?: string[], 
  functionContext?: Record<string, unknown>
): StandardSchemaKeyDefinitionWithSimpleTypes;

/**
 * Gets all evaluated definitions for a field key (for union types)
 * @param key - Field key to get definitions for
 * @param propList - List of specific properties to evaluate
 * @param functionContext - Context object passed to property functions
 * @returns Array of evaluated field definitions
 */
getDefinitions(
  key: string, 
  propList?: string[], 
  functionContext?: Record<string, unknown>
): StandardSchemaKeyDefinitionWithSimpleTypes[];

Usage Examples:

const dynamicSchema = new SimpleSchema({
  name: String,
  description: {
    type: String,
    max: function() {
      return this.key === 'shortDescription' ? 100 : 1000;
    },
    optional: function() {
      return this.field('type').value === 'basic';
    }
  }
});

// Get evaluated definition with context
const context = { 
  key: 'description',
  field: (key) => ({ value: 'premium' })
};

const definition = dynamicSchema.getDefinition('description', undefined, context);
console.log(definition.max); // 1000 (function resolved)
console.log(definition.optional); // false (function resolved)

// Get specific properties only
const limited = dynamicSchema.getDefinition('description', ['max'], context);
console.log('max' in limited); // true
console.log('optional' in limited); // false - not requested

Schema Structure Navigation

Methods for navigating and understanding schema structure.

/**
 * Finds the schema instance that defines a specific key
 * @param key - Field key to search for
 * @returns Tuple of [schema instance, local key] or [null, null] if not found
 */
nearestSimpleSchemaInstance(key: string): [SimpleSchema | null, string | null];

/**
 * Iterates through ancestor schemas that contain a key
 * @param key - Field key to search ancestors for
 * @param func - Function to call for each ancestor schema
 */
forEachAncestorSimpleSchema(
  key: string,
  func: (
    ssInstance: SimpleSchema,
    ancestor: string,
    ancestorGenericKey: string
  ) => void
): void;

/**
 * Gets a scoped schema for an object field
 * @param key - Object field key to get schema for
 * @returns SimpleSchema instance scoped to the object field
 */
getObjectSchema(key: string): SimpleSchema;

/**
 * Gets child keys for object fields
 * @param keyPrefix - Optional prefix to filter keys
 * @returns Array of child key names
 */
objectKeys(keyPrefix?: string): string[];

/**
 * Checks if a key is allowed by the schema
 * @param key - Key to check
 * @returns true if key is defined in schema
 */
allowsKey(key: string): boolean;

/**
 * Checks if a key is inside a blackbox object
 * @param key - Key to check
 * @returns true if key is within a blackbox field
 */
keyIsInBlackBox(key: string): boolean;

/**
 * Gets the raw schema definition passed to constructor
 * Only available if keepRawDefinition option was set to true
 * @returns Raw schema definition object or null
 */
get rawDefinition(): SchemaDefinitionWithShorthand | null;

Usage Examples:

const addressSchema = new SimpleSchema({
  street: String,
  city: String,
  state: String
});

const userSchema = new SimpleSchema({
  name: String,
  address: addressSchema,
  preferences: {
    type: Object,
    blackbox: true
  }
});

// Find which schema defines a key
const [schema, localKey] = userSchema.nearestSimpleSchemaInstance('address.street');
console.log(schema === addressSchema); // true
console.log(localKey); // 'street'

// Get object schema
const addrSchema = userSchema.getObjectSchema('address');
console.log(addrSchema === addressSchema); // true

// Get object keys
const addressKeys = userSchema.objectKeys('address');
console.log(addressKeys); // ['address.street', 'address.city', 'address.state']

const topLevelKeys = userSchema.objectKeys();
console.log(topLevelKeys); // ['name', 'address', 'preferences']

// Check if keys are allowed
console.log(userSchema.allowsKey('name')); // true
console.log(userSchema.allowsKey('address.street')); // true
console.log(userSchema.allowsKey('nonexistent')); // false

// Check blackbox status
console.log(userSchema.keyIsInBlackBox('preferences.theme')); // true
console.log(userSchema.keyIsInBlackBox('address.street')); // false

// Access raw definition (if keepRawDefinition: true was used)
const schemaWithRaw = new SimpleSchema({
  name: String,
  age: Number
}, { keepRawDefinition: true });

console.log(schemaWithRaw.rawDefinition);
// { name: String, age: Number } - exact object passed to constructor

const schemaWithoutRaw = new SimpleSchema({
  name: String,
  age: Number
});
console.log(schemaWithoutRaw.rawDefinition); // null

Field Property Access

Methods to access specific field properties and metadata.

/**
 * Gets simplified type string for a field
 * @param key - Field key to get type for
 * @returns Type string (e.g., 'String', 'Number', 'Array')
 */
getQuickTypeForKey(key: string): string;

/**
 * Gets allowed values array for a field
 * @param key - Field key to get allowed values for
 * @returns Array of allowed values or null if no restriction
 */
getAllowedValuesForKey(key: string): any[] | null;

/**
 * Gets default value for a field
 * @param key - Field key to get default value for
 * @returns Default value or undefined if none set
 */
defaultValue(key: string): unknown;

/**
 * Gets property value for a field with function resolution
 * @param key - Field key
 * @param prop - Property name to get
 * @param functionContext - Context for function-based properties
 * @returns Property value
 */
get(key: string, prop: string, functionContext?: Record<string, unknown>): any;

Usage Examples:

const productSchema = new SimpleSchema({
  name: String,
  category: {
    type: String,
    allowedValues: ['electronics', 'books', 'clothing']
  },
  price: {
    type: Number,
    min: 0
  },
  tags: [String],
  status: {
    type: String,
    defaultValue: 'active'
  },
  priority: {
    type: Number,
    max: function() {
      return this.field('category').value === 'electronics' ? 10 : 5;
    }
  }
});

// Get quick type strings
console.log(productSchema.getQuickTypeForKey('name')); // 'String'
console.log(productSchema.getQuickTypeForKey('price')); // 'Number'
console.log(productSchema.getQuickTypeForKey('tags')); // 'Array'

// Get allowed values
const categories = productSchema.getAllowedValuesForKey('category');
console.log(categories); // ['electronics', 'books', 'clothing']

const nameAllowed = productSchema.getAllowedValuesForKey('name');
console.log(nameAllowed); // null - no restriction

// Get default values
console.log(productSchema.defaultValue('status')); // 'active'
console.log(productSchema.defaultValue('name')); // undefined

// Get property with context
const context = { field: (key) => ({ value: 'electronics' }) };
const maxPriority = productSchema.get('priority', 'max', context);
console.log(maxPriority); // 10 (function resolved with context)

Labels and Messages

Methods for accessing field labels and generating error messages.

/**
 * Sets labels for multiple fields
 * @param labels - Object mapping field keys to label strings or functions
 */
labels(labels: Record<string, string | Function>): void;

/**
 * Gets all field labels
 * @returns Object mapping field keys to label strings
 */
label(): Record<string, string>;

/**
 * Gets label for a specific field
 * @param key - Field key to get label for
 * @returns Label string or null if no label set
 */
label(key: string): string | null;

/**
 * Gets formatted error message for a validation error
 * @param errorInfo - ValidationError object to format
 * @returns Formatted error message string
 */
messageForError(errorInfo: ValidationError): string;

Usage Examples:

const userSchema = new SimpleSchema({
  firstName: String,
  lastName: String,
  email: {
    type: String,
    label: "Email Address"
  },
  age: {
    type: Number,
    label: function() {
      return "Age (years)";
    }
  }
});

// Set multiple labels
userSchema.labels({
  firstName: "First Name",
  lastName: "Last Name"
});

// Get all labels
const allLabels = userSchema.label();
console.log(allLabels);
// {
//   firstName: "First Name",
//   lastName: "Last Name", 
//   email: "Email Address",
//   age: "Age (years)"
// }

// Get specific label
console.log(userSchema.label('email')); // "Email Address"
console.log(userSchema.label('nonexistent')); // null

// Format error message
const error = {
  name: 'email',
  type: 'regEx',
  value: 'invalid-email'
};

const message = userSchema.messageForError(error);
console.log(message); // "Email Address must be a valid email address"

Auto Value Functions

Methods for examining auto value function definitions.

/**
 * Gets details about all autoValue functions in the schema
 * @returns Array of autoValue function details
 */
autoValueFunctions(): AutoValueFunctionDetails[];

/**
 * Gets all blackbox field keys
 * @returns Array of field keys that are marked as blackbox
 */
blackboxKeys(): string[];

interface AutoValueFunctionDetails {
  key: string;
  autoValue: AutoValueFunction;
  fieldName: string;
}

Usage Examples:

const postSchema = new SimpleSchema({
  title: String,
  slug: {
    type: String,
    autoValue() {
      if (this.isInsert && !this.isSet) {
        const title = this.field('title').value;
        return title.toLowerCase().replace(/\s+/g, '-');
      }
    }
  },
  createdAt: {
    type: Date,
    autoValue() {
      if (this.isInsert) {
        return new Date();
      }
    }
  },
  updatedAt: {
    type: Date,
    autoValue() {
      return new Date();
    }
  },
  metadata: {
    type: Object,
    blackbox: true
  }
});

// Get auto value function details
const autoValues = postSchema.autoValueFunctions();
console.log(autoValues.length); // 3
console.log(autoValues.map(av => av.key)); // ['slug', 'createdAt', 'updatedAt']

// Get blackbox keys
const blackboxKeys = postSchema.blackboxKeys();
console.log(blackboxKeys); // ['metadata']

Types

interface ResolvedSchemaDefinition {
  [key: string]: StandardSchemaKeyDefinition;
}

interface StandardSchemaKeyDefinition {
  type: SimpleSchemaGroup;
  optional?: boolean;
  // ... other field properties
}

interface StandardSchemaKeyDefinitionWithSimpleTypes {
  type: SupportedTypes;
  optional?: boolean;
  // ... other field properties with functions resolved
}

type SchemaDefinition = Record<string, SchemaKeyDefinitionWithShorthand>;

interface AutoValueFunctionDetails {
  key: string;
  autoValue: AutoValueFunction;
  fieldName: string;
}

interface ValidationError {
  name: string;
  type: string;
  value: any;
  message?: string;
  [prop: string]: any;
}

Install with Tessl CLI

npx tessl i tessl/npm-simpl-schema

docs

data-cleaning.md

index.md

schema-definition.md

schema-introspection.md

utility-functions.md

validation-context.md

validation.md

tile.json