npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

xsd-lookup

v1.11.0

Published

Multi-schema XSD lookup utility

Readme

XSD schema validation for XML nodes, attributes and values

A comprehensive TypeScript-based XSD schema validation system for XML files, which provides nodes, attributes, and values validation against XSD schemas, including the strict hierarchical dependencies.

Developed to support scripting language validation in X4: Foundations game modding, but can be used for any XML validation needs, based on XSD schemas.

🎯 Features

  • 🔍 XSD-Based Validation: Pure XSD schema validation without hardcoded logic
  • 📊 Comprehensive Attribute Validation: Validates attribute existence, types, and values
  • 🔧 Infrastructure Attribute Filtering: Automatically ignores XML namespace attributes (xmlns, xmlns:*, xsi:*)
  • 🔗 Type Inheritance Support: Handles complex XSD type hierarchies and restrictions
  • 🧩 Hierarchical Context: Getting list of possible child elements based on current element hierarchy
  • 🔄 Previous Sibling Context: Optional previous sibling element name to filter results based on sequence constraints
  • ⚡ Fast Child Validity Check: Direct API to check if a specific child is valid under a parent (with optional previous sibling)
  • 🔀 Union Type Processing: Merges validation rules from multiple member types
  • 📋 Enumeration Support: Complete enumeration value extraction and validation with annotations
  • 🎯 SimpleType Enumeration Discovery: Extract enumeration values from named SimpleTypes, including union types
  • 📏 Range Validation: Numeric and length constraint validation
  • 🗂️ Multi-line Normalization: Handles multi-line XML attribute values correctly
  • 📈 Performance Optimized: Caching and indexing for fast validation
  • 🧰 Singleton Convenience: Use the exported xsdReference instance instead of creating your own

🚀 Quick Start

Installation

npm install xsd_lookup --save

Basic Usage

// ES6 imports (from TypeScript/modern JavaScript)
import { XsdReference } from 'xsd_lookup';

// Initialize the validation system
const xsdRef = new XsdReference();
xsdRef.init('./tests/data/xsd');

const schemaName = 'aiscripts';
const elementName = 'set_value';
const elementHierarchy = ['actions', 'attention', 'aiscript']; // bottom-up (parent -> root)

const elementDefinition = xsdRef.getElementDefinition(schemaName, elementName, elementHierarchy);
console.log(`Element ${elementName} is ${elementDefinition ? 'defined' : 'not defined'} in the schema.`);

// Returns Record<string, EnhancedAttributeInfo>
const elementAttributes = xsdRef.getElementAttributesWithTypes(schemaName, elementName, elementHierarchy);
console.log(`Element ${elementName} has ${Object.keys(elementAttributes).length} attributes.`);

// Static utilities operate on the attribute info map
const attributeValues = XsdReference.getAttributePossibleValues(elementAttributes, 'operation');
console.log(`Possible values for 'operation': ${Array.from(attributeValues.keys()).join(', ')}`);

const checkAttributeValue = XsdReference.validateAttributeValueAgainstRules(elementAttributes, 'operation', 'unknown');
console.log(`Attribute 'operation' value 'unknown' is ${checkAttributeValue.isValid ? 'valid' : 'invalid'}.`);

// Get enumeration values from SimpleType definitions
const classEnums = xsdRef.getSimpleTypeEnumerationValues('common', 'classlookup');
if (classEnums) {
  console.log(`Found ${classEnums.values.length} class types: ${classEnums.values.slice(0, 3).join(', ')}...`);
}

// Clean up resources when done (optional but recommended)
xsdRef.dispose();

Alternatively, use the singleton instance:

import { xsdReference } from 'xsd_lookup';

// Initialize once
xsdReference.init('./tests/data/xsd');

const elementName = 'set_value';
const elementHierarchy = ['actions', 'attention', 'aiscript'];

const elementDefinition = xsdReference.getElementDefinition('aiscripts', elementName, elementHierarchy);
const elementAttributes = xsdReference.getElementAttributesWithTypes('aiscripts', elementName, elementHierarchy); // Record<string, EnhancedAttributeInfo>

// Clean up when done
xsdReference.dispose();

📖 API Reference

🏷️ Type Definitions

Exported Interfaces

// Location of a schema element definition
interface ElementLocation {
  uri: string;         // file:// URI to the XSD file
  line: number;        // 1-based
  column: number;      // 1-based
  lengthOfStartTag: number; // number of characters in the element's start tag
}

// Enhanced attribute information with validation rules
interface EnhancedAttributeInfo {
  name: string;
  type?: string;
  // Location packaged as a single object
  location?: ElementLocation;
  required?: boolean;
  patterns?: string[];
  enumValues?: string[];
  enumValuesAnnotations?: Map<string, string>;
  annotation?: string;
  minLength?: number;
  maxLength?: number;
  minInclusive?: number;
  maxInclusive?: number;
  minExclusive?: number;
  maxExclusive?: number;
}

// Attribute validation result
interface AttributeValidationResult {
  isValid: boolean;
  errorMessage?: string;
  expectedType?: string;
  restrictions?: string[];
  allowedValues?: string[];
}

// Attribute name validation result
interface AttributeNameValidationResult {
  wrongAttributes: string[];
  missingRequiredAttributes: string[];
}

Notes:

  • Methods returning attribute info use an object map keyed by attribute name: Record<string, EnhancedAttributeInfo>.

🏷️ Input parameters

  • schemaName: Name of the schema to operate on (e.g., 'aiscripts'). Equal to the XSD file name without extension.
  • elementName: Name of the XML element to validate (e.g., 'do_if').
  • attributeName: Name of the attribute to validate (e.g., 'value').
  • value: The value to validate against the attribute's XSD rules (e.g., 'player.money gt 1000').
  • hierarchy: Parameter to specify the hierarchy of elements in bottom-up order (from immediate parent to root element) in XML-file. This is crucial for correct validation context.

🏗️ Hierarchy Parameter Usage

Important: All methods that accept a hierarchy parameter expect it in bottom-up order (from immediate parent to root element).

Hierarchy Examples
// For XML structure:
// <aiscript>
//   <attention>
//     <actions>
//       <do_if value="$condition">
//         <debug_text text="message" />
//       </do_if>
//     <set_value name="$value" exact="100" />
//     </actions>
//   </attention>
// </aiscript>

// For 'do_if' element:
const doIfHierarchy = ['actions', 'attention', 'aiscript'];

// For 'debug_text' element:
const debugTextHierarchy = ['do_if', 'actions', 'attention', 'aiscript'];

// Usage:
const attributes = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', doIfHierarchy);
const validation = xsdRef.validateAttributeValue('aiscripts', 'debug_text', 'text', 'Hello', debugTextHierarchy);

XsdReference Class

The main entry point for any operations.

Constructor

new XsdReference()
init(xsdDirectory: string): void

Initialize or reinitialize the instance with the directory that contains your .xsd files. This clears any previously loaded schemas.

const xsdRef = new XsdReference();
xsdRef.init('./tests/data/xsd');
Singleton instance

You can also use a ready-to-use singleton and avoid manual instantiation.

import { xsdReference } from 'xsd_lookup';

xsdReference.init('./tests/data/xsd');
// Then call API methods on xsdReference
const children = xsdReference.getPossibleChildElements('aiscripts', 'actions', ['attention', 'aiscript']);

Core Methods

getSchema(schemaName: string): Schema | null

Load and return a schema by name.

const schema = xsdRef.getSchema('aiscripts');
getAvailableSchemas(): string[]

Get all currently loaded schema types.

const loadedSchemas: string[] = xsdRef.getAvailableSchemas();
// Returns: ['aiscripts', 'md'] (schemas that are currently loaded in memory)
getDiscoverableSchemas(): string[]

Get all discoverable schema files in the XSD directory.

const availableSchemas: string[] = xsdRef.getDiscoverableSchemas();
// Returns: ['aiscripts', 'common', 'md'] (all .xsd files found in directory, without extension)
getElementDefinition(schemaName: string, elementName: string, hierarchy?: string[]): Element | undefined

Get the element definition for a specific element in a schema, considering hierarchy context.

Important: The hierarchy parameter should be provided in bottom-up order (from immediate parent to root element).

// For element structure: <aiscript><attention><actions><set_value>
// Hierarchy for 'set_value' element should be: ['actions', 'attention', 'aiscript']
const elementDef = xsdRef.getElementDefinition('aiscripts', 'set_value', ['actions', 'attention', 'aiscript']);
// Returns: Element definition object or undefined if not found
getElementAttributes(schemaName: string, elementName: string, hierarchy?: string[]): Record<string, Element>

Get basic attribute elements for an element as a map of attribute name to the defining Element node.

Important: The hierarchy parameter should be provided in bottom-up order (from immediate parent to root element).

// For element structure: <aiscript><attention><actions><set_value>
// Hierarchy for 'set_value' element should be: ['actions', 'attention', 'aiscript']
const attributes: Record<string, Element> = xsdRef.getElementAttributes('aiscripts', 'set_value', ['actions', 'attention', 'aiscript']);
// Returns Record<string, EnhancedAttributeInfo> keyed by attribute name:
// {
//   name: Element,   // DOM element reference to xs:attribute definition
//   value: Element,
//   ...
// }
getElementAttributesWithTypes(schemaName: string, elementName: string, hierarchy?: string[], elementDef?: Element): Record<string, EnhancedAttributeInfo>

Get all attributes for an element with complete type information including:

  • Type name
  • Required status
  • Enumeration values (if applicable)
  • Pattern restrictions
  • Numeric/length constraints
  • Attribute definition location (file URI, line, column, lengthOfStartTag)
  • Attribute annotation text (if available)

Performance tip: You can pass an optional elementDef (from getElementDefinition) to avoid re-resolving the element in the schema.

Important: The hierarchy parameter should be provided in bottom-up order (from immediate parent to root element).

// For element structure: <aiscript><attention><actions><do_if>
// Hierarchy for 'do_if' element should be: ['actions', 'attention', 'aiscript']
const attributes = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);
// Returns Record<string, EnhancedAttributeInfo> keyed by attribute name:
// {
//   value: {
//     name: 'value',
//     type: 'expression',
//     required: true,
//     patterns: ['[pattern regex]'],
//     enumValues: undefined,
//     annotation: 'Description text...'(optional),
//     location: {
//       uri: 'file:///C:/path/to/aiscripts.xsd',
//       line: 123,
//       column: 5,
//       lengthOfStartTag: 42
//     }
//   }
// }
validateAttributeValue(schemaName: string, elementName: string, attributeName: string, value: string, hierarchy?: string[]): AttributeValidationResult

Validate an attribute value against XSD constraints.

Important: The hierarchy parameter should be provided in bottom-up order (from immediate parent to root element).

// For element structure: <aiscript><attention><actions><do_if><debug_text>
// Hierarchy for 'debug_text' element should be: ['do_if', 'actions', 'attention', 'aiscript']
const result: AttributeValidationResult = xsdRef.validateAttributeValue('aiscript', 'debug_text', 'chance', '50', ['do_if', 'actions', 'attention', 'aiscript']);
// Returns:
// {
//   isValid: true,
//   expectedType: 'expression',
//   restrictions: ['Pattern: ...']
// }
getPossibleChildElements(schemaName: string, elementName: string, hierarchy?: string[], previousSibling?: string): Map<string, string>

Get possible child elements for a given element, with their annotation text.

Important: The hierarchy parameter should be provided in bottom-up order (from immediate parent to root element). Important: The previousSibling parameter can be used to filter results based on sequence constraints (e.g., if the element must come after a specific sibling).

// For element structure: <aiscript><attention><actions>
// Get possible children of 'actions' element
const children: Map<string, string> = xsdRef.getPossibleChildElements('aiscripts', 'actions', ['attention', 'aiscript']);
// Returns: Map where key is child element name, value is annotation text
// Example: Map { 'do_if' => 'Conditional execution', 'do_while' => 'Loop execution', ... }

// Usage examples:
if (children.size > 0) {
  console.log('Possible child elements:');
  for (const [elementName, annotation] of children) {
    console.log(`  ${elementName}: ${annotation || '(no description)'}`);
  }
}
isValidChild(schemaName: string, elementName: string, parentName: string, parentHierarchy?: string[], previousSibling?: string): boolean

Check if a specific element is valid as a child of a given parent in the provided hierarchy, using the same engine and sequence/choice constraints as getPossibleChildElements, but without building the full child set.

Important: The parentHierarchy parameter should be provided in bottom-up order (from immediate parent to root element). Important: The optional previousSibling parameter narrows the check to respect sequence constraints within the parent’s content model.

// Validate if 'do_else' can follow 'do_if' inside <actions>
const ok = xsdRef.isValidChild(
  'aiscripts',
  'do_else',
  'actions',
  ['attention', 'aiscript'],
  'do_if'
);
console.log('do_else after do_if is', ok ? 'allowed' : 'not allowed');

// Check if 'do_if' can start under <actions> (no previousSibling)
const canStart = xsdRef.isValidChild('aiscripts', 'do_if', 'actions', ['attention', 'aiscript']);
console.log('do_if at start of <actions> is', canStart ? 'allowed' : 'not allowed');
getSimpleTypesWithBaseType(schemaName: string, baseType: string): string[]

Get all simple types that use a specific type as their base.

// Find all simple types based on 'lvalueexpression'
const derivedTypes: string[] = xsdRef.getSimpleTypesWithBaseType('aiscripts', 'lvalueexpression');
// Returns: ['expression', 'objectref', 'paramname', ...] (types that extend lvalueexpression)

// Find all types based on xs:string
const stringTypes: string[] = xsdRef.getSimpleTypesWithBaseType('common', 'xs:string');
// Returns: ['name', 'comment', 'text', ...] (string-based types)
getSimpleTypeEnumerationValues(schemaName: string, simpleTypeName: string): { values: string[], annotations: Map<string, string> } | null

Get enumeration values for a named SimpleType, including support for union types.

Union Type Support: This method properly handles union types by extracting enumeration values from all member types and combining them into a single result.

// Get enumeration values from a simple enumeration type
const quadrantResult = xsdRef.getSimpleTypeEnumerationValues('common', 'quadrantlookup');
// Returns:
// {
//   values: ['quadrant.none', 'quadrant.front', 'quadrant.back'],
//   annotations: Map {
//     'quadrant.none' => 'No specific quadrant',
//     'quadrant.front' => 'Front quadrant',
//     'quadrant.back' => 'Back quadrant'
//   }
// }

// Get enumeration values from a union type (combines multiple enumerations)
const classResult = xsdRef.getSimpleTypeEnumerationValues('common', 'classlookup');
// Returns:
// {
//   values: ['class.component', 'class.buildprocessor', 'class.ship', 'class.station', ...],
//   annotations: Map {
//     'class.component' => 'Component',
//     'class.buildprocessor' => 'Build processor',
//     'class.ship' => 'Ship',
//     // ... 80+ values from union of 'positionalclasslookup' and 'expression' types
//   }
// }

// Handle non-existent or non-enumeration types
const nonExistent = xsdRef.getSimpleTypeEnumerationValues('common', 'nonexistent');
// Returns: null

// Usage example:
if (classResult) {
  console.log(`Found ${classResult.values.length} enumeration values`);
  for (const value of classResult.values) {
    const annotation = classResult.annotations.get(value);
    console.log(`  ${value}: ${annotation || '(no description)'}`);
  }

  // Check if a specific value exists
  if (classResult.values.includes('class.ship')) {
    console.log('class.ship is a valid enumeration value');
  }
}
dispose(): void

Clear all internal caches to release resources.

// Get a schema instance
const schema = xsdRef.getSchema('aiscripts');

// Use the schema for validation...
const result = schema.validateAttributeValue('do_if', 'value', 'condition');

// Clean up schema resources when done
schema.dispose();

Note: Not recommended for frequent use in performance-sensitive scenarios.

Static Methods

XsdReference.getElementLocation(element: Element): ElementLocation

Get the source file URI and 1-based position for a schema element definition.

// Obtain an element definition first
const def = xsdRef.getElementDefinition('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);

if (def) {
  const loc = XsdReference.getElementLocation(def);
  // Example output: file:///C:/path/to/tests/data/xsd/aiscripts.xsd:123:5
  console.log(`${loc.uri}:${loc.line}:${loc.column}`);
  // Start tag length is also available when you need precise range handling
  // console.log('start tag length:', loc.lengthOfStartTag);
}

Notes:

  • uri is a file:// URI pointing to the XSD file that defined the element.
  • line and column are 1-based positions within that file.
  • lengthOfStartTag is the character length of the element’s start tag (from '<' to the matching '>').
XsdReference.validateAttributeNames(attributeInfos: Record<string, EnhancedAttributeInfo>, providedAttributes: string[]): AttributeNameValidationResult

Validate attribute names against schema definitions. This static method checks which attributes are valid and identifies missing required attributes.

🔧 Infrastructure Attribute Handling: XML infrastructure attributes (xmlns, xmlns:*, xsi:*) are automatically filtered out before validation.

// Get attribute info first
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);
const providedAttrs = ['value', 'chance', 'xmlns:xsi', 'invalid_attr'];

const nameValidation: AttributeNameValidationResult = XsdReference.validateAttributeNames(attributeInfos, providedAttrs);
// Returns:
// {
//   wrongAttributes: ['invalid_attr'],           // Infrastructure attrs filtered out
//   missingRequiredAttributes: ['negate', ...]                // Required attributes missing
// }
// Note: 'xmlns:xsi' is ignored and doesn't appear in wrongAttributes
XsdReference.validateAttributeValueAgainstRules(attributeInfos: Record<string, EnhancedAttributeInfo>, attributeName: string, attributeValue: string)

Validate an attribute value against all XSD rules (patterns, enumerations, ranges, etc.). This static method provides detailed validation with rule violation information.

🔧 Infrastructure Attribute Handling: XML infrastructure attributes (xmlns, xmlns:*, xsi:*) are automatically ignored and always return { isValid: true }.

// Get attribute info first
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);

const valueValidation = XsdReference.validateAttributeValueAgainstRules(
  attributeInfos,
  'value',
  'player.money gt 1000'
);
// Returns:
// {
//   isValid: true,
//   errorMessage: undefined,        // Only present if invalid
//   violatedRules: undefined        // Only present if invalid - array of specific rule violations
// }

// Example with invalid value:
const invalidValidation = XsdReference.validateAttributeValueAgainstRules(
  attributeInfos,
  'chance',
  '150'
);
// Returns:
// {
//   isValid: false,
//   errorMessage: "Value must be <= 100",
//   violatedRules: ["Value must be <= 100"]
// }

// Infrastructure attributes are ignored:
const infraValidation = XsdReference.validateAttributeValueAgainstRules(
  attributeInfos,
  'xmlns:xsi',
  'http://www.w3.org/2001/XMLSchema-instance'
);
// Returns:
// {
//   isValid: true
// }
XsdReference.getAttributePossibleValues(attributeInfos: Record<string, EnhancedAttributeInfo>, attributeName: string): Map<string, string>

Get all possible enumeration values for an attribute, if it has enumeration restrictions.

🔧 Infrastructure Attribute Handling: XML infrastructure attributes always return an empty Map.

// Get attribute info first
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'set_value', ['actions', 'attention', 'aiscript']);

const possibleValues: Map<string, string> = XsdReference.getAttributePossibleValues(attributeInfos, 'operator');
// Returns: Map<string, string> where key is enum value, value is annotation
// Example: Map { 'set' => 'Set value', 'add' => 'Add to value', 'subtract' => 'Subtract from value', ... }
// Returns: Map() (empty map if no enumeration exists or if it's an infrastructure attribute)

// Usage examples:
if (possibleValues.size > 0) {
  console.log('Available values:');
  for (const [value, annotation] of possibleValues) {
    console.log(`  ${value}: ${annotation || '(no description)'}`);
  }

  // Get just the values as an array
  const valueArray = Array.from(possibleValues.keys());
  console.log('Values only:', valueArray); // ['set', 'add', 'subtract', 'insert']
}
XsdReference.filterAttributesByType(attributeInfos: Record<string, EnhancedAttributeInfo>, attributeType: string): string[]

Filter attributes by their XSD type (e.g., 'xs:string', 'xs:int', 'expression').

🔧 Infrastructure Attribute Handling: XML infrastructure attributes are automatically excluded from results.

// Get attribute info first
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);

const stringAttributes: string[] = XsdReference.filterAttributesByType(attributeInfos, 'xs:string');
// Returns: ['comment', 'name'] (example - attributes with xs:string type)

const expressionAttributes: string[] = XsdReference.filterAttributesByType(attributeInfos, 'expression');
// Returns: ['value', 'chance'] (example - attributes with expression type)
XsdReference.filterAttributesByRestriction(attributeInfos: Record<string, EnhancedAttributeInfo>, restrictionType: 'enumeration' | 'pattern' | 'length' | 'range'): string[]

Filter attributes by the type of XSD restriction they have.

🔧 Infrastructure Attribute Handling: XML infrastructure attributes are automatically excluded from results.

// Get attribute info first
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);

const enumAttributes: string[] = XsdReference.filterAttributesByRestriction(attributeInfos, 'enumeration');
// Returns: ['operator', 'type'] (example - attributes with enumeration restrictions)

const patternAttributes: string[] = XsdReference.filterAttributesByRestriction(attributeInfos, 'pattern');
// Returns: ['ref', 'name'] (example - attributes with pattern restrictions)

const rangeAttributes: string[] = XsdReference.filterAttributesByRestriction(attributeInfos, 'range');
// Returns: ['min', 'max'] (example - attributes with numeric range restrictions)

const lengthAttributes: string[] = XsdReference.filterAttributesByRestriction(attributeInfos, 'length');
// Returns: ['text'] (example - attributes with length restrictions)
extractAnnotationText(schemaName: string, element: Element): string | undefined (instance)

Extract annotation text from an XML element in the context of a specific schema. This is used by the test runner to track annotation coverage and is also available for consumers.

// This is typically used internally, but can be useful for custom schema processing
const element: Element = /* DOM element from XSD */;
const annotation: string | undefined = xsdRef.extractAnnotationText('aiscripts', element);
// Returns: "Description text from xs:annotation/xs:documentation" or undefined

// Example usage with element definitions:
const elementDef = xsdRef.getElementDefinition('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);
if (elementDef) {
  const description = xsdRef.extractAnnotationText('aiscripts', elementDef);
  console.log('Element description:', description || 'No description available');
}

Typical Validation Workflow

// 1. Get schema and attribute info once
const xsdRef = new XsdReference();
xsdRef.init('./tests/data/xsd');
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);

// 2. Validate attribute names (fast, no schema lookup needed)
// Infrastructure attributes (xmlns, xsi:) are automatically filtered out
const nameValidation: AttributeNameValidationResult = XsdReference.validateAttributeNames(attributeInfos, ['value', 'xmlns:xsi', 'invalid_attr']);
if (nameValidation.wrongAttributes.length > 0) {
  console.error('Invalid attributes:', nameValidation.wrongAttributes); // Only shows 'invalid_attr'
}

// 3. Validate attribute values (fast, no schema lookup needed)
// Infrastructure attributes automatically return { isValid: true }
for (const attrName of Object.keys(attributeInfos)) {
  const valueValidation = XsdReference.validateAttributeValueAgainstRules(
    attributeInfos,
    attrName,
    attributeValue
  );
  if (!valueValidation.isValid) {
    console.error(`Invalid value for ${attrName}:`, valueValidation.violatedRules);
  }
}

// 4. Use helper methods to analyze attributes by type or restriction
const enumAttributes: string[] = XsdReference.filterAttributesByRestriction(attributeInfos, 'enumeration');
const possibleValues: Map<string, string> = XsdReference.getAttributePossibleValues(attributeInfos, 'operator');

// Work with possible values Map
if (possibleValues.size > 0) {
  console.log('Operator values:', Array.from(possibleValues.keys()));
  // Check if a specific value is valid
  if (possibleValues.has('eq')) {
    console.log('eq annotation:', possibleValues.get('eq') || '(no description)');
  }
}

// Alternatively, using the singleton
// import { xsdReference } from 'xsd_lookup';
// xsdReference.init('./tests/data/xsd');
// const attributeInfos = xsdReference.getElementAttributesWithTypes('aiscripts', 'do_if', ['actions', 'attention', 'aiscript']);

Schema Class

There is a main engine for validating XML files against XSD schemas. It provides detailed validation capabilities for a specific XSD schema.

Note: Not recommended to use directly, prefer using XsdReference for schema management.

XsdDetector Class

Automatically detects the appropriate XSD schema for XML files.

getSchemaName(xmlFilePath: string): string | null

Detect schema name from XML file path and content.

const schemaName = XsdDetector.getSchemaName('./scripts/my-script.xml');
// Returns: 'aiscripts'

� Infrastructure Attribute Handling

The validation system automatically handles XML infrastructure attributes to focus validation on content-relevant attributes:

What are Infrastructure Attributes?

Infrastructure attributes are XML namespace and schema-related attributes that are part of the XML specification itself, not your content:

  • xmlns - Default namespace declaration
  • xmlns:* - Namespace prefix declarations (e.g., xmlns:xsi)
  • xsi:* - XML Schema Instance attributes (e.g., xsi:schemaLocation)

Automatic Filtering

All static validation methods automatically filter out infrastructure attributes:

<!-- Example XML with infrastructure attributes -->
<do_if value="player.money gt 1000"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="..."
       chance="50">
  <!-- content -->
</do_if>
// Only 'value' and 'chance' are validated; xmlns/xsi attributes are ignored
const attributeInfos = xsdRef.getElementAttributesWithTypes('aiscripts', 'do_if', hierarchy);
const nameValidation = XsdReference.validateAttributeNames(
  attributeInfos,
  ['value', 'chance', 'xmlns:xsi', 'xsi:schemaLocation']
);
// Result: { wrongAttributes: [], missingRequiredAttributes: [] }
// Infrastructure attributes don't appear in wrongAttributes

const valueValidation = XsdReference.validateAttributeValueAgainstRules(
  attributeInfos,
  'xmlns:xsi',
  'http://www.w3.org/2001/XMLSchema-instance'
);
// Result: { isValid: true } - Infrastructure attributes always pass

🔧 Development

Project Structure

├── src/                   # TypeScript source files
│   ├── Schema.ts          # Core validation engine
│   ├── XsdReference.ts    # Main API interface
│   └── XsdDetector.ts     # Schema auto-detection
├── dist/                  # Compiled JavaScript output
├── tests/                 # Comprehensive test suite
│   ├── data/              # Test data and schemas
│   │   ├── xsd/           # XSD schema definitions
│   │   ├── aiscripts/     # AI script test files
│   │   └── md/            # Mission director test files
│   └── test_all_files_comprehensive.js
├── package.json           # Project configuration
└── tsconfig.json          # TypeScript configuration

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • X4 Foundations by Egosoft for the complex and rich modding system
  • XML Schema (XSD) specification for comprehensive validation standards
  • TypeScript and Node.js ecosystem for excellent development tools

Performance Tips

  • Reuse XsdReference instances when validating multiple files with the same schemas
  • Call dispose() only when completely finished with validation tasks
  • Use static methods (XsdReference.validateAttributeNames, etc.) for batch operations with pre-fetched attribute info