@abapify/ts-xsd 0.3.6 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["isAbstractElement","resolveElementInfo","findSubstitutes"],"sources":["../src/walker/index.ts","../src/xml/parse.ts","../src/xml/build-utils.ts","../src/xml/build.ts","../src/xml/typed.ts"],"sourcesContent":["/**\n * Schema Walker - Generator-based traversal for W3C Schema objects\n *\n * Provides a single source of truth for schema traversal logic.\n * All consumers (xml/parse, xml/build, interface-generator) use these\n * generators instead of reimplementing traversal.\n *\n * @example\n * ```typescript\n * // Find a complexType by name (stops at first match)\n * for (const { ct, schema } of walkComplexTypes(rootSchema)) {\n * if (ct.name === 'PersonType') return { type: ct, schema };\n * }\n *\n * // Iterate all elements in a complexType (handles inheritance)\n * for (const { element, optional, array } of walkElements(complexType, schema)) {\n * console.log(element.name, optional ? '?' : '', array ? '[]' : '');\n * }\n * ```\n */\n\n// Using schema-like types because walker needs to work with both:\n// 1. Parsed schemas at runtime (Schema from xsd/types.ts)\n// 2. `as const` literals for type inference (readonly arrays)\n// The \"Like\" types are loose enough to accept both.\nimport type {\n SchemaLike,\n ComplexTypeLike,\n ElementLike,\n AttributeLike,\n GroupLike,\n SimpleTypeLike,\n} from '../xsd/schema-like';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** Result of walking complexTypes */\nexport type ComplexTypeEntry = {\n readonly ct: ComplexTypeLike;\n readonly schema: SchemaLike;\n};\n\n/** Result of walking simpleTypes */\nexport type SimpleTypeEntry = {\n readonly st: SimpleTypeLike;\n readonly schema: SchemaLike;\n};\n\n/** Result of walking elements */\nexport type ElementEntry = {\n readonly element: ElementLike;\n /** Element is optional (minOccurs=0 or inside choice) */\n readonly optional: boolean;\n /** Element is array (maxOccurs > 1 or unbounded) */\n readonly array: boolean;\n /** Source group type */\n readonly source: 'sequence' | 'choice' | 'all' | 'extension';\n /** Schema where the element is defined (for namespace prefix resolution) */\n readonly schema: SchemaLike;\n};\n\n/** Result of walking attributes */\nexport type AttributeEntry = {\n readonly attribute: AttributeLike;\n /** Attribute is required (use=\"required\") */\n readonly required: boolean;\n /** Schema where the attribute is defined (for namespace prefix resolution) */\n readonly schema: SchemaLike;\n};\n\n/** Result of walking top-level elements */\nexport type TopLevelElementEntry = {\n readonly element: ElementLike;\n readonly schema: SchemaLike;\n};\n\n/** Options for schema-level walkers */\nexport type WalkOptions = {\n /** Only recurse into $includes, not $imports (default: false) */\n readonly includesOnly?: boolean;\n};\n\n// =============================================================================\n// Schema-level Walkers (traverse $imports and $includes)\n// =============================================================================\n\n/**\n * Walk all complexTypes in a schema and its $imports/$includes (depth-first).\n *\n * @param schema - Root schema to start from\n * @param options - Walk options (e.g., includesOnly to skip $imports)\n * @yields ComplexType with the schema it was found in\n *\n * @example\n * ```typescript\n * function findComplexType(name: string, schema: SchemaLike) {\n * for (const { ct, schema: s } of walkComplexTypes(schema)) {\n * if (ct.name === name) return { type: ct, schema: s };\n * }\n * }\n * ```\n */\nexport function* walkComplexTypes(\n schema: SchemaLike,\n options: WalkOptions = {},\n): Generator<ComplexTypeEntry> {\n // Current schema's complexTypes\n const complexTypes = schema.complexType;\n if (complexTypes) {\n if (Array.isArray(complexTypes)) {\n for (const ct of complexTypes) {\n yield { ct, schema };\n }\n } else {\n // Object format: { TypeName: { ... } }\n for (const [name, ct] of Object.entries(complexTypes)) {\n yield { ct: { ...ct, name } as ComplexTypeLike, schema };\n }\n }\n }\n\n // Yield complexTypes from redefine blocks (these override types from included schemas)\n // Redefine types are yielded FIRST so findComplexType finds them before the original\n if (schema.redefine) {\n for (const redef of schema.redefine) {\n if (redef.complexType) {\n for (const ct of redef.complexType) {\n yield { ct, schema };\n }\n }\n }\n }\n\n // Yield complexTypes from override blocks (XSD 1.1)\n if (schema.override) {\n for (const ovr of schema.override) {\n if (ovr.complexType) {\n for (const ct of ovr.complexType) {\n yield { ct, schema };\n }\n }\n }\n }\n\n // Recurse into $includes (same namespace - content is merged)\n if (schema.$includes) {\n for (const included of schema.$includes) {\n yield* walkComplexTypes(included, options);\n }\n }\n\n // Recurse into $imports (different namespace) - skip if includesOnly\n if (!options.includesOnly && schema.$imports) {\n for (const imported of schema.$imports) {\n yield* walkComplexTypes(imported, options);\n }\n }\n}\n\n/**\n * Walk all simpleTypes in a schema and its $imports/$includes.\n */\nexport function* walkSimpleTypes(\n schema: SchemaLike,\n options: WalkOptions = {},\n): Generator<SimpleTypeEntry> {\n const simpleTypes = schema.simpleType;\n if (simpleTypes) {\n if (Array.isArray(simpleTypes)) {\n for (const st of simpleTypes) {\n yield { st, schema };\n }\n } else {\n for (const [name, st] of Object.entries(simpleTypes)) {\n yield { st: { ...st, name } as SimpleTypeLike, schema };\n }\n }\n }\n\n // Yield simpleTypes from redefine blocks (these override types from included schemas)\n if (schema.redefine) {\n for (const redef of schema.redefine) {\n if (redef.simpleType) {\n for (const st of redef.simpleType) {\n yield { st, schema };\n }\n }\n }\n }\n\n // Yield simpleTypes from override blocks (XSD 1.1)\n if (schema.override) {\n for (const ovr of schema.override) {\n if (ovr.simpleType) {\n for (const st of ovr.simpleType) {\n yield { st, schema };\n }\n }\n }\n }\n\n // Recurse into $includes (same namespace)\n if (schema.$includes) {\n for (const included of schema.$includes) {\n yield* walkSimpleTypes(included, options);\n }\n }\n\n // Recurse into $imports (different namespace) - skip if includesOnly\n if (!options.includesOnly && schema.$imports) {\n for (const imported of schema.$imports) {\n yield* walkSimpleTypes(imported, options);\n }\n }\n}\n\n/**\n * Walk all top-level elements in a schema and its $imports/$includes.\n */\nexport function* walkTopLevelElements(\n schema: SchemaLike,\n options: WalkOptions = {},\n): Generator<TopLevelElementEntry> {\n if (schema.element) {\n for (const element of schema.element) {\n yield { element, schema };\n }\n }\n\n // Recurse into $includes (same namespace)\n if (schema.$includes) {\n for (const included of schema.$includes) {\n yield* walkTopLevelElements(included, options);\n }\n }\n\n // Recurse into $imports (different namespace) - skip if includesOnly\n if (!options.includesOnly && schema.$imports) {\n for (const imported of schema.$imports) {\n yield* walkTopLevelElements(imported, options);\n }\n }\n}\n\n// =============================================================================\n// Lookup Helpers (use walkers internally)\n// =============================================================================\n\n/**\n * Find a complexType by name, searching schema and $imports.\n * Returns both the type AND the schema it was found in (important for inheritance).\n */\nexport function findComplexType(\n name: string,\n schema: SchemaLike,\n): ComplexTypeEntry | undefined {\n for (const entry of walkComplexTypes(schema)) {\n if (entry.ct.name === name) {\n return entry;\n }\n }\n return undefined;\n}\n\n/**\n * Find a simpleType by name, searching schema and $imports.\n */\nexport function findSimpleType(\n name: string,\n schema: SchemaLike,\n): SimpleTypeEntry | undefined {\n for (const entry of walkSimpleTypes(schema)) {\n if (entry.st.name === name) {\n return entry;\n }\n }\n return undefined;\n}\n\n/**\n * Find a top-level element by name, searching schema and $imports.\n */\nexport function findElement(\n name: string,\n schema: SchemaLike,\n): TopLevelElementEntry | undefined {\n for (const entry of walkTopLevelElements(schema)) {\n if (entry.element.name === name) {\n return entry;\n }\n }\n return undefined;\n}\n\n// =============================================================================\n// ComplexType Content Walkers\n// =============================================================================\n\n/**\n * Walk all elements in a complexType, handling:\n * - sequence, choice, all groups\n * - Nested groups (recursive)\n * - complexContent/extension inheritance\n * - Group references\n *\n * @param ct - ComplexType to walk\n * @param schema - Schema context (for resolving base types and group refs)\n * @yields Elements with metadata (optional, array, source)\n */\nexport function* walkElements(\n ct: ComplexTypeLike,\n schema: SchemaLike,\n): Generator<ElementEntry> {\n // Handle complexContent/extension (inheritance)\n if (ct.complexContent?.extension) {\n const ext = ct.complexContent.extension;\n\n // First yield inherited elements from base type\n if (ext.base) {\n const baseName = stripNsPrefix(ext.base);\n const baseEntry = findComplexType(baseName, schema);\n if (baseEntry) {\n // Use the schema where base was found for proper context\n yield* walkElements(baseEntry.ct, baseEntry.schema);\n }\n }\n\n // Then yield extension's own elements (defined in current schema)\n yield* walkGroup(ext.sequence, 'sequence', schema);\n yield* walkGroup(ext.choice, 'choice', schema);\n yield* walkGroup(ext.all, 'all', schema);\n\n // Handle group reference in extension\n if (ext.group?.ref) {\n yield* walkGroupRef(ext.group.ref, schema);\n }\n return;\n }\n\n // Handle complexContent/restriction\n if (ct.complexContent?.restriction) {\n const rest = ct.complexContent.restriction;\n yield* walkGroup(rest.sequence, 'sequence', schema);\n yield* walkGroup(rest.choice, 'choice', schema);\n yield* walkGroup(rest.all, 'all', schema);\n if (rest.group?.ref) {\n yield* walkGroupRef(rest.group.ref, schema);\n }\n return;\n }\n\n // Direct content (no complexContent)\n yield* walkGroup(ct.sequence, 'sequence', schema);\n yield* walkGroup(ct.choice, 'choice', schema);\n yield* walkGroup(ct.all, 'all', schema);\n\n // Handle group reference\n if (ct.group?.ref) {\n yield* walkGroupRef(ct.group.ref, schema);\n }\n}\n\n/**\n * Walk elements in a group (sequence/choice/all), handling nested groups.\n */\nfunction* walkGroup(\n group: GroupLike | undefined,\n source: 'sequence' | 'choice' | 'all',\n schema: SchemaLike,\n parentOptional = false,\n parentArray = false,\n): Generator<ElementEntry> {\n if (!group) return;\n\n // Check group-level minOccurs/maxOccurs\n const groupOptional =\n parentOptional || group.minOccurs === 0 || group.minOccurs === '0';\n const groupArray = parentArray || isArray(group);\n\n // Elements in choice are always optional (only one is selected)\n const choiceOptional = source === 'choice';\n\n // Yield direct elements\n if (group.element) {\n for (const element of group.element) {\n const optional =\n choiceOptional ||\n groupOptional ||\n element.minOccurs === 0 ||\n element.minOccurs === '0';\n const array = groupArray || isArray(element);\n\n // Handle element reference to abstract element with substitution group\n if (element.ref) {\n const refName = stripNsPrefix(element.ref);\n const refEntry = findElement(refName, schema);\n\n if (refEntry && isAbstractElement(refEntry.element)) {\n // Abstract element - yield substitutes if found in this schema\n const substitutes = findSubstitutes(refName, schema);\n if (substitutes.length > 0) {\n for (const sub of substitutes) {\n yield { element: sub, optional, array, source, schema };\n }\n continue;\n }\n // No substitutes found in this schema - yield the original element\n // so the parser can handle substitution using the root schema\n }\n }\n\n yield { element, optional, array, source, schema };\n }\n }\n\n // Recurse into nested sequences\n if (group.sequence) {\n const sequences = Array.isArray(group.sequence)\n ? group.sequence\n : [group.sequence];\n for (const nested of sequences) {\n yield* walkGroup(nested, 'sequence', schema, groupOptional, groupArray);\n }\n }\n\n // Recurse into nested choices (elements become optional)\n if (group.choice) {\n const choices = Array.isArray(group.choice) ? group.choice : [group.choice];\n for (const nested of choices) {\n yield* walkGroup(\n nested,\n 'choice',\n schema,\n true,\n groupArray || isArray(nested),\n );\n }\n }\n\n // Handle group references within the group\n if (group.group) {\n const refs = Array.isArray(group.group) ? group.group : [group.group];\n for (const ref of refs) {\n if (ref.ref) {\n yield* walkGroupRef(\n ref.ref,\n schema,\n groupOptional || choiceOptional,\n groupArray || isArray(ref),\n );\n }\n }\n }\n}\n\n/**\n * Walk elements from a group reference (xs:group ref=\"...\").\n */\nfunction* walkGroupRef(\n ref: string,\n schema: SchemaLike,\n parentOptional = false,\n parentArray = false,\n): Generator<ElementEntry> {\n const groupName = stripNsPrefix(ref);\n const group = findGroup(groupName, schema);\n\n if (group) {\n // Group can have sequence/choice/all\n if (group.sequence) {\n yield* walkGroup(\n group.sequence,\n 'sequence',\n schema,\n parentOptional,\n parentArray,\n );\n }\n if (group.choice) {\n yield* walkGroup(group.choice, 'choice', schema, true, parentArray);\n }\n if (group.all) {\n yield* walkGroup(group.all, 'all', schema, parentOptional, parentArray);\n }\n }\n}\n\n/**\n * Walk all attributes in a complexType, handling:\n * - Direct attributes\n * - complexContent/extension attributes\n * - simpleContent/extension attributes\n * - Inherited attributes from base type\n * - AttributeGroup references\n */\nexport function* walkAttributes(\n ct: ComplexTypeLike,\n schema: SchemaLike,\n): Generator<AttributeEntry> {\n // Handle complexContent/extension\n if (ct.complexContent?.extension) {\n const ext = ct.complexContent.extension;\n\n // Inherited attributes from base\n if (ext.base) {\n const baseName = stripNsPrefix(ext.base);\n const baseEntry = findComplexType(baseName, schema);\n if (baseEntry) {\n yield* walkAttributes(baseEntry.ct, baseEntry.schema);\n }\n }\n\n // Extension's own attributes (resolve refs)\n if (ext.attribute) {\n for (const attr of ext.attribute) {\n const resolved = resolveAttribute(attr, schema);\n if (resolved) {\n yield {\n attribute: resolved,\n required: resolved.use === 'required',\n schema,\n };\n }\n }\n }\n\n // AttributeGroup references\n yield* walkAttributeGroupRefs(ext.attributeGroup, schema);\n return;\n }\n\n // Handle simpleContent/extension\n if (ct.simpleContent?.extension) {\n const ext = ct.simpleContent.extension;\n if (ext.attribute) {\n for (const attr of ext.attribute) {\n const resolved = resolveAttribute(attr, schema);\n if (resolved) {\n yield {\n attribute: resolved,\n required: resolved.use === 'required',\n schema,\n };\n }\n }\n }\n yield* walkAttributeGroupRefs(ext.attributeGroup, schema);\n return;\n }\n\n // Direct attributes (resolve refs)\n if (ct.attribute) {\n for (const attr of ct.attribute) {\n const resolved = resolveAttribute(attr, schema);\n if (resolved) {\n yield {\n attribute: resolved,\n required: resolved.use === 'required',\n schema,\n };\n }\n }\n }\n\n // AttributeGroup references\n yield* walkAttributeGroupRefs(ct.attributeGroup, schema);\n}\n\n/**\n * Walk attributes from attributeGroup references.\n */\nfunction* walkAttributeGroupRefs(\n refs: readonly unknown[] | undefined,\n schema: SchemaLike,\n): Generator<AttributeEntry> {\n if (!refs) return;\n\n for (const ref of refs) {\n const refObj = ref as { ref?: string };\n if (refObj.ref) {\n const groupName = stripNsPrefix(refObj.ref);\n const group = findAttributeGroup(groupName, schema);\n if (group?.attribute) {\n for (const attribute of group.attribute as AttributeLike[]) {\n yield { attribute, required: attribute.use === 'required', schema };\n }\n }\n }\n }\n}\n\n// =============================================================================\n// Group/AttributeGroup Finders\n// =============================================================================\n\n/**\n * Find a named group (xs:group) by name.\n */\nfunction findGroup(\n name: string,\n schema: SchemaLike,\n): { sequence?: GroupLike; choice?: GroupLike; all?: GroupLike } | undefined {\n // Search in current schema\n if (schema.group) {\n for (const g of schema.group as Array<{\n name?: string;\n sequence?: GroupLike;\n choice?: GroupLike;\n all?: GroupLike;\n }>) {\n if (g.name === name) return g;\n }\n }\n\n // Search in $includes (same namespace)\n if (schema.$includes) {\n for (const included of schema.$includes) {\n const found = findGroup(name, included);\n if (found) return found;\n }\n }\n\n // Search in $imports (different namespace)\n if (schema.$imports) {\n for (const imported of schema.$imports) {\n const found = findGroup(name, imported);\n if (found) return found;\n }\n }\n\n return undefined;\n}\n\n/**\n * Find a top-level attribute by name.\n * Searches current schema and $imports.\n */\nfunction findAttribute(\n name: string,\n schema: SchemaLike,\n): AttributeLike | undefined {\n // Search in current schema's top-level attributes\n const schemaWithAttrs = schema as { attribute?: readonly AttributeLike[] };\n if (schemaWithAttrs.attribute) {\n for (const attr of schemaWithAttrs.attribute) {\n if (attr.name === name) return attr;\n }\n }\n\n // Search in $includes (same namespace)\n if (schema.$includes) {\n for (const included of schema.$includes) {\n const found = findAttribute(name, included);\n if (found) return found;\n }\n }\n\n // Search in $imports (different namespace)\n if (schema.$imports) {\n for (const imported of schema.$imports) {\n const found = findAttribute(name, imported);\n if (found) return found;\n }\n }\n\n return undefined;\n}\n\n/**\n * Resolve an attribute - handles both direct attributes and refs.\n * Returns the resolved attribute with its name.\n */\nfunction resolveAttribute(\n attribute: AttributeLike,\n schema: SchemaLike,\n): AttributeLike | undefined {\n // If attribute has a ref, resolve it\n if (attribute.ref) {\n const refName = stripNsPrefix(attribute.ref);\n const resolved = findAttribute(refName, schema);\n if (resolved) {\n // Merge ref's use with resolved attribute\n return {\n ...resolved,\n use: attribute.use ?? resolved.use,\n } as AttributeLike;\n }\n // Fallback: create attribute with ref name\n return {\n name: refName,\n type: 'xs:string',\n use: attribute.use,\n } as AttributeLike;\n }\n // Direct attribute\n return attribute;\n}\n\n/**\n * Find an attributeGroup by name.\n */\nfunction findAttributeGroup(\n name: string,\n schema: SchemaLike,\n): { attribute?: readonly AttributeLike[] } | undefined {\n if (schema.attributeGroup) {\n for (const g of schema.attributeGroup as Array<{\n name?: string;\n attribute?: readonly AttributeLike[];\n }>) {\n if (g.name === name) return g;\n }\n }\n\n // Search in $includes (same namespace)\n if (schema.$includes) {\n for (const included of schema.$includes) {\n const found = findAttributeGroup(name, included);\n if (found) return found;\n }\n }\n\n // Search in $imports (different namespace)\n if (schema.$imports) {\n for (const imported of schema.$imports) {\n const found = findAttributeGroup(name, imported);\n if (found) return found;\n }\n }\n\n return undefined;\n}\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\n/**\n * Strip namespace prefix from a QName (e.g., \"tns:PersonType\" -> \"PersonType\")\n */\nexport function stripNsPrefix(name: string): string {\n const colonIndex = name.indexOf(':');\n return colonIndex >= 0 ? name.slice(colonIndex + 1) : name;\n}\n\n/**\n * Check if element/group has maxOccurs > 1 (is array)\n */\nfunction isArray(item: { maxOccurs?: number | string | 'unbounded' }): boolean {\n if (item.maxOccurs === 'unbounded') return true;\n if (typeof item.maxOccurs === 'number') return item.maxOccurs > 1;\n if (typeof item.maxOccurs === 'string') {\n if (item.maxOccurs === 'unbounded') return true;\n const num = parseInt(item.maxOccurs, 10);\n return !isNaN(num) && num > 1;\n }\n return false;\n}\n\n// =============================================================================\n// Substitution Group Support\n// =============================================================================\n\n/**\n * Check if an element is abstract\n */\nexport function isAbstractElement(element: ElementLike): boolean {\n return (\n (element as { abstract?: boolean | string }).abstract === true ||\n (element as { abstract?: boolean | string }).abstract === 'true'\n );\n}\n\n/**\n * Find all elements that substitute for a given abstract element.\n * This handles XSD substitution groups where concrete elements can\n * substitute for an abstract element.\n */\nexport function findSubstitutes(\n abstractElementName: string,\n schema: SchemaLike,\n): ElementLike[] {\n const substitutes: ElementLike[] = [];\n\n // Walk all top-level elements looking for substitutionGroup\n for (const { element } of walkTopLevelElements(schema)) {\n const subGroup = (element as { substitutionGroup?: string })\n .substitutionGroup;\n if (subGroup) {\n const subGroupName = stripNsPrefix(subGroup);\n if (subGroupName === abstractElementName) {\n substitutes.push(element);\n }\n }\n }\n\n return substitutes;\n}\n","/**\n * XML Parser for W3C Schema\n *\n * Parse XML string to typed JavaScript object using W3C-compliant Schema definition.\n * Uses the walker module for schema traversal.\n */\n\nimport { DOMParser } from '@xmldom/xmldom';\nimport type {\n InferParsedSchema,\n SchemaLike,\n ComplexTypeLike,\n ElementLike,\n} from '../infer';\nimport {\n findComplexType,\n findElement,\n walkElements,\n walkAttributes,\n stripNsPrefix,\n} from '../walker';\nimport {\n getAttributeValue,\n getChildElements,\n getAllChildElements,\n getTextContent,\n getLocalName,\n} from './dom-utils';\n\n/**\n * Find all elements that substitute for a given abstract element\n * Searches current schema and all $imports\n */\nfunction findSubstitutingElements(\n abstractElementName: string,\n schema: SchemaLike,\n): Array<{ element: ElementLike; schema: SchemaLike }> {\n const results: Array<{ element: ElementLike; schema: SchemaLike }> = [];\n\n // Helper to check elements in a schema\n const checkSchema = (s: SchemaLike) => {\n const elements = s.element;\n if (!elements) return;\n\n for (const el of elements) {\n if (el.substitutionGroup) {\n const subGroupName = stripNsPrefix(el.substitutionGroup);\n if (subGroupName === abstractElementName) {\n results.push({ element: el, schema: s });\n }\n }\n }\n };\n\n // Check current schema\n checkSchema(schema);\n\n // Check all imported schemas\n const imports = (schema as { $imports?: SchemaLike[] }).$imports;\n if (imports) {\n for (const imported of imports) {\n checkSchema(imported);\n // Recursively check nested imports\n const nestedResults = findSubstitutingElements(\n abstractElementName,\n imported,\n );\n results.push(...nestedResults);\n }\n }\n\n return results;\n}\n\n/**\n * Check if an element is abstract\n * Searches current schema and all $imports\n */\nfunction isAbstractElement(elementName: string, schema: SchemaLike): boolean {\n // Check current schema\n const elements = schema.element;\n if (elements) {\n for (const el of elements) {\n if (el.name === elementName && el.abstract === true) {\n return true;\n }\n }\n }\n\n // Check imported schemas\n const imports = (schema as { $imports?: SchemaLike[] }).$imports;\n if (imports) {\n for (const imported of imports) {\n if (isAbstractElement(elementName, imported)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nimport type { Element } from '@xmldom/xmldom';\n\ntype XmlElement = Element;\n\n/**\n * Parse XML string to typed object using schema definition\n */\nexport function parse<T extends SchemaLike>(\n schema: T,\n xml: string,\n): InferParsedSchema<T> {\n const doc = new DOMParser().parseFromString(xml, 'text/xml');\n const root = doc?.documentElement;\n\n if (!root) {\n throw new Error('Invalid XML: missing root element');\n }\n\n // Get root element name from XML (strip namespace prefix)\n const rootLocalName = getLocalName(root);\n\n // Find the element declaration for this root\n const elementEntry = findElementByName(schema, rootLocalName);\n\n if (!elementEntry) {\n throw new Error(`Schema missing element declaration for: ${rootLocalName}`);\n }\n\n // Check for inline complexType first\n const inlineComplexType = (\n elementEntry.element as { complexType?: ComplexTypeLike }\n ).complexType;\n if (inlineComplexType) {\n const content = parseElement(\n root,\n inlineComplexType,\n elementEntry.schema,\n schema,\n );\n // Wrap result with root element name for type discrimination\n return { [rootLocalName]: content } as InferParsedSchema<T>;\n }\n\n // Get the type name (strip namespace prefix if present)\n const typeName = stripNsPrefix(\n elementEntry.element.type || elementEntry.element.name || '',\n );\n\n // Find the complexType definition (searches current schema and $imports)\n const typeEntry = findComplexType(typeName, schema);\n\n if (!typeEntry) {\n throw new Error(`Schema missing complexType for: ${typeName}`);\n }\n\n const content = parseElement(root, typeEntry.ct, typeEntry.schema, schema);\n // Wrap result with root element name for type discrimination\n return { [rootLocalName]: content } as InferParsedSchema<T>;\n}\n\n/**\n * Find element declaration by name (case-insensitive fallback)\n */\nfunction findElementByName(\n schema: SchemaLike,\n name: string,\n): { element: ElementLike; schema: SchemaLike } | undefined {\n // Try exact match first using walker\n const exact = findElement(name, schema);\n if (exact) return exact;\n\n // Try case-insensitive match in current schema\n const elements = schema.element;\n if (elements) {\n const lowerName = name.toLowerCase();\n const found = elements.find((el) => el.name?.toLowerCase() === lowerName);\n if (found) return { element: found, schema };\n }\n\n return undefined;\n}\n\n/**\n * Parse a single element using its complexType definition\n * Uses walker to iterate elements and attributes (handles inheritance automatically)\n * @param node - The XML element to parse\n * @param typeDef - The complexType definition for this element\n * @param schema - The schema where typeDef is defined (for type resolution)\n * @param rootSchema - The root schema (for substitution group lookups)\n */\nfunction parseElement(\n node: XmlElement,\n typeDef: ComplexTypeLike,\n schema: SchemaLike,\n rootSchema: SchemaLike,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n // Handle simpleContent (text content with attributes)\n if (typeDef.simpleContent?.extension) {\n return parseSimpleContent(node, typeDef, schema, rootSchema);\n }\n\n // Parse attributes using walker (handles inheritance)\n for (const { attribute } of walkAttributes(typeDef, schema)) {\n if (!attribute.name) continue;\n const value = getAttributeValue(node, attribute.name);\n if (value !== null) {\n result[attribute.name] = convertValue(value, attribute.type || 'string');\n } else if (attribute.default !== undefined) {\n result[attribute.name] = convertValue(\n String(attribute.default),\n attribute.type || 'string',\n );\n }\n }\n\n // Parse child elements using walker (handles inheritance, groups, refs)\n for (const { element, array } of walkElements(typeDef, schema)) {\n const resolved = resolveElementInfo(element, schema);\n if (!resolved) continue;\n\n // Check if this is a reference to an abstract element (substitution group head)\n // Use rootSchema for substitution lookups since substitutes can be in any imported schema\n const isAbstract = isAbstractElement(resolved.name, rootSchema);\n if (isAbstract) {\n // Find all elements that substitute for this abstract element\n const substitutes = findSubstitutingElements(resolved.name, rootSchema);\n\n // Get all child elements and check if any match a substituting element\n const allChildren = getAllChildElements(node);\n for (const child of allChildren) {\n const childName = getLocalName(child);\n const substitute = substitutes.find(\n (s) => s.element.name === childName,\n );\n if (substitute && substitute.element.name) {\n const subTypeName = substitute.element.type\n ? stripNsPrefix(substitute.element.type)\n : undefined;\n result[substitute.element.name] = parseChildValue(\n child,\n subTypeName,\n substitute.schema,\n rootSchema,\n );\n }\n }\n } else {\n // Normal element handling\n const children = getChildElements(node, resolved.name);\n\n if (array || children.length > 1) {\n // Array element\n const values = children.map((child) =>\n parseChildValue(child, resolved.typeName, schema, rootSchema),\n );\n if (values.length > 0) {\n result[resolved.name] = values;\n }\n } else if (children.length === 1) {\n // Single element\n result[resolved.name] = parseChildValue(\n children[0],\n resolved.typeName,\n schema,\n rootSchema,\n );\n }\n }\n }\n\n return result;\n}\n\n/**\n * Parse simpleContent (text content with attributes)\n */\nfunction parseSimpleContent(\n node: XmlElement,\n typeDef: ComplexTypeLike,\n _schema: SchemaLike,\n _rootSchema: SchemaLike,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const simpleContent = typeDef.simpleContent;\n if (!simpleContent?.extension) {\n return result;\n }\n const ext = simpleContent.extension;\n\n // Get text content as $value\n const textContent = getTextContent(node);\n const baseType = ext.base ? stripNsPrefix(ext.base) : 'string';\n result.$value = convertValue(textContent, baseType);\n\n // Parse attributes from simpleContent extension\n if (ext.attribute) {\n for (const attrDef of ext.attribute) {\n if (!attrDef.name) continue;\n const value = getAttributeValue(node, attrDef.name);\n if (value !== null) {\n result[attrDef.name] = convertValue(value, attrDef.type || 'string');\n } else if (attrDef.default !== undefined) {\n result[attrDef.name] = convertValue(\n String(attrDef.default),\n attrDef.type || 'string',\n );\n }\n }\n }\n\n return result;\n}\n\n/**\n * Resolve element info (name and type), handling ref\n */\nfunction resolveElementInfo(\n element: ElementLike,\n schema: SchemaLike,\n): { name: string; typeName: string | undefined } | undefined {\n // Direct element with name\n if (element.name) {\n return {\n name: element.name,\n typeName: element.type ? stripNsPrefix(element.type) : undefined,\n };\n }\n\n // Handle element reference - get type from referenced element declaration\n if (element.ref) {\n const refName = stripNsPrefix(element.ref);\n const refElement = findElement(refName, schema);\n if (refElement) {\n const name = refElement.element.name ?? refName;\n return {\n name,\n typeName: refElement.element.type\n ? stripNsPrefix(refElement.element.type)\n : undefined,\n };\n }\n // Fallback: use ref name, no type\n return { name: refName, typeName: undefined };\n }\n\n return undefined;\n}\n\n/**\n * Parse a child element's value (either complex type or simple value)\n */\nfunction parseChildValue(\n child: XmlElement,\n typeName: string | undefined,\n schema: SchemaLike,\n rootSchema: SchemaLike,\n): unknown {\n // Find nested complexType if this field has a complex type\n const nestedType = typeName ? findComplexType(typeName, schema) : undefined;\n\n if (nestedType) {\n return parseElement(child, nestedType.ct, nestedType.schema, rootSchema);\n }\n\n return convertValue(getTextContent(child) || '', typeName || 'string');\n}\n\n/**\n * Convert string value to typed value based on XSD type\n */\nfunction convertValue(value: string, type: string): unknown {\n const localType = stripNsPrefix(type);\n\n switch (localType) {\n case 'int':\n case 'integer':\n case 'decimal':\n case 'float':\n case 'double':\n case 'short':\n case 'long':\n case 'byte':\n case 'unsignedInt':\n case 'unsignedShort':\n case 'unsignedLong':\n case 'unsignedByte':\n case 'positiveInteger':\n case 'negativeInteger':\n case 'nonPositiveInteger':\n case 'nonNegativeInteger':\n return Number(value);\n\n case 'boolean':\n return value === 'true' || value === '1';\n\n case 'date':\n case 'dateTime':\n return value; // Keep as string, let consumer parse if needed\n\n default:\n return value;\n }\n}\n","/**\n * Shared utilities for XML builders\n */\n\nimport type { Document, Element } from '@xmldom/xmldom';\nimport { DOMImplementation } from '@xmldom/xmldom';\nimport type { SchemaLike, ComplexTypeLike, ElementLike } from '../infer';\nimport { findComplexType, stripNsPrefix } from '../walker';\n\n// Re-export xmldom types for use in other modules\nexport type XmlDocument = Document;\nexport type XmlElement = Element;\n\nexport interface BuildOptions {\n /** Include XML declaration (default: true) */\n xmlDecl?: boolean;\n /** XML encoding (default: utf-8) */\n encoding?: string;\n /** Pretty print with indentation (default: false) */\n pretty?: boolean;\n /** Namespace prefix to use (default: from schema or none) */\n prefix?: string;\n /** Root element name to use (default: auto-detect from data) */\n rootElement?: string;\n}\n\n/**\n * Get namespace prefix from schema $xmlns declarations\n */\nexport function getSchemaPrefix(schema: SchemaLike): string | undefined {\n if (!schema.$xmlns || !schema.targetNamespace) return undefined;\n\n for (const [prefix, uri] of Object.entries(schema.$xmlns)) {\n if (uri === schema.targetNamespace && prefix) {\n return prefix;\n }\n }\n return undefined;\n}\n\n/**\n * Create XML document with namespace\n */\nexport function createXmlDocument(schema: SchemaLike): XmlDocument {\n const impl = new DOMImplementation();\n const ns = schema.targetNamespace || null;\n return impl.createDocument(ns, '', null);\n}\n\n/**\n * Collect namespace declarations from a schema and its $imports/$includes recursively.\n *\n * Gathers all $xmlns prefix→URI mappings from the schema tree.\n * Unused declarations are cleaned up later by stripUnusedNamespaces()\n * after the XML tree is built — that approach is generic and doesn't\n * require any domain-specific knowledge.\n */\nfunction collectAllNamespaces(\n schema: SchemaLike,\n collected: Map<string, string> = new Map(),\n visited: Set<unknown> = new Set(),\n): Map<string, string> {\n if (visited.has(schema)) return collected;\n visited.add(schema);\n\n if (schema.$xmlns) {\n for (const [pfx, uri] of Object.entries(schema.$xmlns)) {\n if (!collected.has(pfx)) {\n collected.set(pfx, uri as string);\n }\n }\n }\n\n const imports = (schema as { $imports?: SchemaLike[] }).$imports;\n if (imports) {\n for (const imported of imports) {\n collectAllNamespaces(imported, collected, visited);\n }\n }\n\n const includes = (schema as { $includes?: SchemaLike[] }).$includes;\n if (includes) {\n for (const included of includes) {\n collectAllNamespaces(included, collected, visited);\n }\n }\n\n return collected;\n}\n\n/**\n * Create root element with namespace declarations\n *\n * When elementFormDefault=\"unqualified\", the root element should NOT have\n * a namespace prefix. This is important for formats like abapGit where\n * the root element (abapGit) is unqualified but child elements may have prefixes.\n */\nexport function createRootElement(\n doc: XmlDocument,\n elementName: string,\n schema: SchemaLike,\n prefix: string | undefined,\n): XmlElement {\n const ns = schema.targetNamespace || null;\n\n // Check elementFormDefault - when \"unqualified\", root element should NOT have prefix\n // This follows the abapGit pattern where root is unqualified but xmlns:asx is declared\n const elementFormDefault = (schema as { elementFormDefault?: string })\n .elementFormDefault;\n const usePrefix = elementFormDefault === 'unqualified' ? undefined : prefix;\n\n const rootTag = usePrefix ? `${usePrefix}:${elementName}` : elementName;\n const root = doc.createElement(rootTag);\n\n // Add namespace declaration for the prefix (even if root doesn't use it)\n // This allows child elements to use the prefix\n if (ns && prefix) {\n root.setAttribute(`xmlns:${prefix}`, ns);\n } else if (ns && !prefix) {\n root.setAttribute('xmlns', ns);\n }\n\n // Collect ALL namespace declarations from schema and its $imports recursively\n // This ensures that namespaces used by inherited types are declared\n const allNamespaces = collectAllNamespaces(schema);\n\n for (const [pfx, uri] of allNamespaces) {\n if (pfx && pfx !== prefix) {\n root.setAttribute(`xmlns:${pfx}`, uri);\n } else if (!pfx) {\n root.setAttribute('xmlns', uri);\n }\n }\n\n return root;\n}\n\n/**\n * Remove xmlns declarations from the root element for prefixes that are\n * not actually used anywhere in the document tree.\n *\n * This prevents emitting unused namespace declarations (e.g. xmlns:abapsource,\n * xmlns:abapoo) that come from the schema's $imports chain but aren't\n * referenced by any element or attribute in the built XML.\n *\n * The prefix that maps to the schema's own targetNamespace is always\n * preserved — even when elementFormDefault=\"unqualified\" causes the root\n * element to be emitted without a prefix, the xmlns declaration is still\n * required for the document to be in the correct namespace.\n */\n/**\n * Add namespace prefix from a qualified name to the set (if present).\n */\nfunction addPrefixFromName(name: string, usedPrefixes: Set<string>): void {\n const colon = name.indexOf(':');\n if (colon > 0) {\n usedPrefixes.add(name.substring(0, colon));\n }\n}\n\n/**\n * Collect namespace prefixes referenced by attributes on a single element\n * (xmlns declarations are skipped — they declare rather than use prefixes).\n */\nfunction collectPrefixesFromAttributes(\n node: XmlElement,\n usedPrefixes: Set<string>,\n): void {\n if (!node.attributes) return;\n for (const attr of Array.from(node.attributes)) {\n if (!attr.name.startsWith('xmlns:') && attr.name !== 'xmlns') {\n addPrefixFromName(attr.name, usedPrefixes);\n }\n }\n}\n\n/**\n * Collect prefixes used by elements and attributes in the tree (recursive walk).\n */\nfunction collectUsedPrefixes(\n node: XmlElement,\n usedPrefixes: Set<string>,\n): void {\n addPrefixFromName(node.tagName, usedPrefixes);\n collectPrefixesFromAttributes(node, usedPrefixes);\n\n if (node.childNodes) {\n for (const child of Array.from(node.childNodes)) {\n if (child.nodeType === 1) {\n collectUsedPrefixes(child as XmlElement, usedPrefixes);\n }\n }\n }\n}\n\n/**\n * Collect xmlns:prefix attribute names on the root element whose prefix\n * is not in the used-prefixes set.\n */\nfunction findUnusedXmlnsAttrs(\n root: XmlElement,\n usedPrefixes: Set<string>,\n): string[] {\n const toRemove: string[] = [];\n if (!root.attributes) return toRemove;\n for (const attr of Array.from(root.attributes)) {\n if (attr.name.startsWith('xmlns:')) {\n const pfx = attr.name.substring(6);\n if (!usedPrefixes.has(pfx)) {\n toRemove.push(attr.name);\n }\n }\n }\n return toRemove;\n}\n\nexport function stripUnusedNamespaces(\n root: XmlElement,\n schema?: SchemaLike,\n): void {\n // Collect all prefixes actually used by elements and attributes in the tree.\n // Always preserve the prefix for the schema's own targetNamespace.\n const usedPrefixes = new Set<string>();\n\n if (schema?.targetNamespace && schema.$xmlns) {\n for (const [pfx, uri] of Object.entries(schema.$xmlns)) {\n if (pfx && uri === schema.targetNamespace) {\n usedPrefixes.add(pfx);\n }\n }\n }\n\n collectUsedPrefixes(root, usedPrefixes);\n\n for (const name of findUnusedXmlnsAttrs(root, usedPrefixes)) {\n root.removeAttribute(name);\n }\n}\n\n/**\n * Find element declaration by name or auto-detect from data\n */\nexport function findElementDeclaration(\n schema: SchemaLike,\n rootElement?: string,\n _data?: Record<string, unknown>,\n): ElementLike {\n if (rootElement) {\n const elementDecl = schema.element?.find((e) => e.name === rootElement);\n if (!elementDecl) {\n throw new Error(`Element '${rootElement}' not found in schema`);\n }\n return elementDecl;\n }\n\n // Auto-detect from data\n const elements = schema.element;\n if (!elements || elements.length === 0) {\n throw new Error('Schema has no element declarations');\n }\n\n if (elements.length === 1) {\n return elements[0];\n }\n\n // Multiple elements - find best match (caller should provide findMatchingElement)\n return elements[0];\n}\n\n/**\n * Get complexType for an element declaration\n */\nexport function getElementComplexType(\n elementDecl: ElementLike,\n schema: SchemaLike,\n): { type: ComplexTypeLike; schema: SchemaLike } {\n if (elementDecl.complexType) {\n return { type: elementDecl.complexType as ComplexTypeLike, schema };\n }\n\n if (elementDecl.type) {\n const typeName = stripNsPrefix(elementDecl.type);\n const typeEntry = findComplexType(typeName, schema);\n if (!typeEntry) {\n throw new Error(`Schema missing complexType for: ${typeName}`);\n }\n return { type: typeEntry.ct, schema: typeEntry.schema };\n }\n\n throw new Error(\n `Element ${elementDecl.name} has no type or inline complexType`,\n );\n}\n\n/**\n * Format value for XML output\n */\nexport function formatValue(value: unknown, type: string): string {\n if (value instanceof Date) {\n const localType = stripNsPrefix(type);\n return localType === 'date'\n ? value.toISOString().split('T')[0]\n : value.toISOString();\n }\n\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false';\n }\n\n return String(value);\n}\n\n/**\n * Simple XML formatter (basic indentation)\n *\n * Keeps text content inline: <tag>text</tag>\n * Only adds newlines for nested elements\n */\nexport function formatXml(xml: string): string {\n let formatted = '';\n let indent = 0;\n // Tokenize into tags and text using linear scan (avoids regex backtracking).\n const parts: string[] = [];\n let pos = 0;\n while (pos < xml.length) {\n if (xml.charCodeAt(pos) === 60 /* '<' */) {\n const end = xml.indexOf('>', pos + 1);\n if (end === -1) {\n parts.push(xml.slice(pos));\n break;\n }\n parts.push(xml.slice(pos, end + 1));\n pos = end + 1;\n } else {\n const next = xml.indexOf('<', pos);\n if (next === -1) {\n parts.push(xml.slice(pos));\n break;\n }\n if (next > pos) parts.push(xml.slice(pos, next));\n pos = next;\n }\n }\n let lastWasText = false;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const nextPart = parts[i + 1];\n\n if (part.startsWith('<?')) {\n formatted += part + '\\n';\n lastWasText = false;\n } else if (part.startsWith('</')) {\n indent = Math.max(0, indent - 1);\n if (lastWasText) {\n // Text content before closing tag - keep inline\n formatted += part + '\\n';\n } else {\n formatted += ' '.repeat(indent) + part + '\\n';\n }\n lastWasText = false;\n } else if (part.startsWith('<') && part.endsWith('/>')) {\n formatted += ' '.repeat(indent) + part + '\\n';\n lastWasText = false;\n } else if (part.startsWith('<')) {\n formatted += ' '.repeat(indent) + part;\n if (!part.includes('</')) {\n indent++;\n }\n // Check if next part is text content (not a tag)\n if (nextPart && !nextPart.startsWith('<')) {\n // Don't add newline - text content follows\n } else {\n formatted += '\\n';\n }\n lastWasText = false;\n } else {\n // Text content - keep inline with opening tag\n const trimmed = part.trim();\n if (trimmed) {\n formatted += trimmed;\n lastWasText = true;\n }\n }\n }\n\n return formatted.trim();\n}\n\n/**\n * Add XML declaration to string\n */\nexport function addXmlDeclaration(xml: string, encoding: string): string {\n return `<?xml version=\"1.0\" encoding=\"${encoding}\"?>\\n${xml}`;\n}\n","/**\n * XML Builder for W3C Schema (Walker-based implementation)\n *\n * Build XML string from typed JavaScript object using W3C-compliant Schema definition.\n * Uses the walker module for schema traversal.\n */\n\nimport { XMLSerializer } from '@xmldom/xmldom';\nimport type { SchemaLike, ComplexTypeLike, ElementLike } from '../infer';\nimport {\n findComplexType,\n findElement,\n walkElements,\n walkAttributes,\n stripNsPrefix,\n} from '../walker';\nimport {\n type XmlDocument,\n type XmlElement,\n getSchemaPrefix,\n createXmlDocument,\n createRootElement,\n stripUnusedNamespaces,\n formatValue,\n formatXml,\n} from './build-utils';\n\n/**\n * Collect all namespace prefixes from a schema and its $imports chain\n */\nfunction collectAllXmlns(\n schema: SchemaLike,\n visited = new Set<SchemaLike>(),\n): Record<string, string> {\n if (visited.has(schema)) return {};\n visited.add(schema);\n\n const result: Record<string, string> = {};\n\n // Add this schema's $xmlns\n const xmlns = (schema as { $xmlns?: Record<string, string> }).$xmlns;\n if (xmlns) {\n Object.assign(result, xmlns);\n }\n\n // Recursively collect from $imports\n const imports = (schema as { $imports?: SchemaLike[] }).$imports;\n if (imports) {\n for (const imported of imports) {\n Object.assign(result, collectAllXmlns(imported, visited));\n }\n }\n\n return result;\n}\n\n/**\n * Get the namespace prefix for a schema's targetNamespace from the root schema's $xmlns\n * and all imported schemas' $xmlns (for inherited attributes)\n */\nfunction getPrefixForSchema(\n schema: SchemaLike,\n rootSchema: SchemaLike,\n): string | undefined {\n const targetNs = (schema as { targetNamespace?: string }).targetNamespace;\n if (!targetNs) return undefined;\n\n // Collect all xmlns from root schema and its imports\n const allXmlns = collectAllXmlns(rootSchema);\n\n // Find prefix that maps to this namespace\n for (const [prefix, ns] of Object.entries(allXmlns)) {\n if (ns === targetNs) {\n return prefix;\n }\n }\n return undefined;\n}\n\nexport type { BuildOptions } from './build-utils';\nexport { type XmlDocument, type XmlElement } from './build-utils';\n\nimport type { BuildOptions } from './build-utils';\n\n/**\n * Build XML string from typed object using schema definition\n */\nexport function build<T extends SchemaLike>(\n schema: T,\n data: unknown,\n options: BuildOptions = {},\n): string {\n const { xmlDecl = true, encoding = 'utf-8', pretty = false } = options;\n const prefix = options.prefix ?? getSchemaPrefix(schema);\n\n const doc = createXmlDocument(schema);\n\n // Find the element declaration - either by name or by matching data\n let elementDecl: ElementLike | undefined;\n let elementSchema: SchemaLike = schema;\n let elementData = data as Record<string, unknown>;\n\n if (options.rootElement) {\n // Search in main schema and $imports\n const found = findElement(options.rootElement, schema);\n if (!found) {\n throw new Error(`Element '${options.rootElement}' not found in schema`);\n }\n elementDecl = found.element;\n elementSchema = found.schema;\n // If data is wrapped with root element name, unwrap it\n if (elementData[options.rootElement] !== undefined) {\n elementData = elementData[options.rootElement] as Record<string, unknown>;\n }\n } else {\n // Check if data is wrapped with element name (new format from parse())\n // Data format: { elementName: { ...content } }\n const dataKeys = Object.keys(elementData);\n if (dataKeys.length === 1) {\n const potentialElementName = dataKeys[0];\n const found = findElement(potentialElementName, schema);\n if (found) {\n elementDecl = found.element;\n elementSchema = found.schema;\n // Unwrap the data\n elementData = elementData[potentialElementName] as Record<\n string,\n unknown\n >;\n }\n }\n\n // Fallback to matching by data structure if not wrapped\n if (!elementDecl) {\n elementDecl = findMatchingElement(elementData, schema);\n if (!elementDecl) {\n throw new Error('Schema has no element declarations');\n }\n }\n }\n\n // Get the complexType - either inline or by reference\n let rootType: ComplexTypeLike;\n let rootSchema: SchemaLike = elementSchema;\n\n if (elementDecl.complexType) {\n rootType = elementDecl.complexType as ComplexTypeLike;\n } else if (elementDecl.type) {\n const typeName = stripNsPrefix(elementDecl.type);\n const rootTypeEntry = findComplexType(typeName, elementSchema);\n if (!rootTypeEntry) {\n throw new Error(`Schema missing complexType for: ${typeName}`);\n }\n rootType = rootTypeEntry.ct;\n rootSchema = rootTypeEntry.schema;\n } else {\n throw new Error(\n `Element ${elementDecl.name} has no type or inline complexType`,\n );\n }\n\n // Create root element with namespace declarations\n const elementName = elementDecl.name ?? elementDecl.ref;\n if (!elementName) {\n throw new Error('Element declaration has no name or ref');\n }\n const root = createRootElement(doc, elementName, schema, prefix);\n\n buildElement(doc, root, elementData, rootType, rootSchema, schema, prefix);\n\n // Remove xmlns declarations for prefixes not actually used in the built XML\n stripUnusedNamespaces(root, schema);\n\n // Ensure root element is never self-closing (SAP ADT requires closing tags)\n // If root has no child nodes, add an empty text node to force </element> instead of />\n if (!root.hasChildNodes()) {\n root.appendChild(doc.createTextNode(''));\n }\n\n doc.appendChild(root);\n\n let xml = new XMLSerializer().serializeToString(doc);\n\n if (xmlDecl) {\n xml = `<?xml version=\"1.0\" encoding=\"${encoding}\"?>\\n${xml}`;\n }\n\n if (pretty) {\n xml = formatXml(xml);\n }\n\n return xml;\n}\n\n/**\n * Find the element declaration that best matches the data structure.\n * Searches in the main schema first, then in $imports.\n */\nfunction findMatchingElement(\n data: Record<string, unknown>,\n schema: SchemaLike,\n): ElementLike | undefined {\n const dataKeys = new Set(Object.keys(data));\n let bestMatch: ElementLike | undefined;\n let bestScore = -1;\n\n // Helper to score an element against the data\n const scoreElement = (\n element: ElementLike,\n searchSchema: SchemaLike,\n ): number => {\n let ct: ComplexTypeLike | undefined;\n let ctSchema: SchemaLike = searchSchema;\n\n // Handle inline complexType\n if (element.complexType) {\n ct = element.complexType as ComplexTypeLike;\n } else if (element.type) {\n const typeName = stripNsPrefix(element.type);\n const typeEntry = findComplexType(typeName, searchSchema);\n if (typeEntry) {\n ct = typeEntry.ct;\n ctSchema = typeEntry.schema;\n }\n }\n\n if (!ct) return 0;\n\n // Get all field names from this type using walker\n const typeFields = new Set<string>();\n for (const { element: el } of walkElements(ct, ctSchema)) {\n if (el.name) typeFields.add(el.name);\n }\n for (const { attribute } of walkAttributes(ct, ctSchema)) {\n if (attribute.name) typeFields.add(attribute.name);\n }\n\n let score = 0;\n dataKeys.forEach((key) => {\n if (typeFields.has(key)) score++;\n });\n return score;\n };\n\n // Search in main schema first\n const elements = schema.element;\n if (elements && elements.length > 0) {\n for (const element of elements) {\n const score = scoreElement(element, schema);\n if (score > bestScore) {\n bestScore = score;\n bestMatch = element;\n }\n }\n }\n\n // Search in $imports if no good match found in main schema\n const imports = schema.$imports as SchemaLike[] | undefined;\n if (imports) {\n for (const importedSchema of imports) {\n const importedElements = importedSchema.element;\n if (!importedElements) continue;\n\n for (const element of importedElements) {\n const score = scoreElement(element, importedSchema);\n if (score > bestScore) {\n bestScore = score;\n bestMatch = element;\n }\n }\n }\n }\n\n // Fallback to first element if no match found\n if (!bestMatch && elements && elements.length > 0) {\n return elements[0];\n }\n\n return bestMatch;\n}\n\n/**\n * Build element content using its complexType definition\n * Uses walker to iterate elements and attributes (handles inheritance automatically)\n * @param rootSchema - The original schema passed to build(), used for substitution group lookup\n */\nfunction buildElement(\n doc: XmlDocument,\n node: XmlElement,\n data: Record<string, unknown>,\n typeDef: ComplexTypeLike,\n schema: SchemaLike,\n rootSchema: SchemaLike,\n prefix: string | undefined,\n): void {\n // Build attributes using walker (handles inheritance)\n // The walker now returns the schema where each attribute is defined,\n // which is critical for correct namespace prefix resolution in inherited types\n for (const { attribute, schema: attrSchema } of walkAttributes(\n typeDef,\n schema,\n )) {\n if (!attribute.name) continue;\n const value = data[attribute.name];\n if (value !== undefined && value !== null) {\n // Check attributeFormDefault - attributes get prefix when \"qualified\"\n // Use the schema where the attribute is defined (from walker), not the current schema\n const attributeFormDefault = (\n attrSchema as { attributeFormDefault?: string }\n ).attributeFormDefault;\n const attrForm = (attribute as { form?: string }).form;\n\n let attrName = attribute.name;\n // Priority: 1. Per-attribute form, 2. Schema attributeFormDefault\n if (\n attrForm === 'qualified' ||\n (attrForm !== 'unqualified' && attributeFormDefault === 'qualified')\n ) {\n // Get prefix for the attribute's defining schema's namespace\n const attrPrefix = getPrefixForSchema(attrSchema, rootSchema);\n if (attrPrefix) {\n attrName = `${attrPrefix}:${attribute.name}`;\n }\n }\n node.setAttribute(\n attrName,\n formatValue(value, attribute.type || 'string'),\n );\n }\n }\n\n // Build child elements using walker (handles inheritance, groups, refs)\n // The walker returns schema per element so we can resolve the correct namespace prefix\n // for elements inherited from imported schemas (e.g., packageRef from adtcore)\n for (const { element, schema: elementDefSchema } of walkElements(\n typeDef,\n schema,\n )) {\n // Check if this is a ref to an abstract element\n if (element.ref) {\n const refName = stripNsPrefix(element.ref);\n const refElement = findElement(refName, elementDefSchema);\n\n if (refElement && refElement.element.abstract) {\n // Abstract element - find substitutes in data using rootSchema\n const substitutes = findSubstitutes(refName, rootSchema);\n for (const substitute of substitutes) {\n const subName = substitute.element.name;\n if (!subName) continue;\n\n const value = data[subName];\n if (value !== undefined) {\n const typeName = substitute.element.type\n ? stripNsPrefix(substitute.element.type)\n : undefined;\n buildField(\n doc,\n node,\n value,\n subName,\n typeName,\n substitute.schema,\n rootSchema,\n prefix,\n );\n }\n }\n continue;\n }\n }\n\n const resolved = resolveElementInfo(element, elementDefSchema);\n if (!resolved) continue;\n\n const value = data[resolved.dataKey];\n if (value !== undefined) {\n buildFieldWithTagName(\n doc,\n node,\n value,\n resolved.tagName,\n resolved.typeName,\n resolved.inlineComplexType,\n resolved.elementSchema,\n rootSchema,\n prefix,\n resolved.form,\n );\n }\n }\n}\n\n/**\n * Resolve element info (name and type), handling ref\n *\n * Returns:\n * - tagName: The XML tag name to use (may include prefix like \"asx:abap\")\n * - dataKey: The key to look up in data object (local name without prefix)\n * - typeName: The type name for building nested content (if type attribute)\n * - inlineComplexType: The inline complexType definition (if present)\n * - elementSchema: The schema where the element was found\n * - form: Per-element form override (\"qualified\" or \"unqualified\")\n */\nfunction resolveElementInfo(\n element: ElementLike,\n schema: SchemaLike,\n):\n | {\n tagName: string;\n dataKey: string;\n typeName: string | undefined;\n inlineComplexType: ComplexTypeLike | undefined;\n elementSchema: SchemaLike;\n form: string | undefined;\n }\n | undefined {\n // Direct element with name\n if (element.name) {\n return {\n tagName: element.name,\n dataKey: element.name,\n typeName: element.type ? stripNsPrefix(element.type) : undefined,\n inlineComplexType: element.complexType as ComplexTypeLike | undefined,\n elementSchema: schema,\n form: (element as { form?: string }).form,\n };\n }\n\n // Handle element reference - get type from referenced element declaration\n // IMPORTANT: Keep the original ref (with prefix) for the tag name\n // This ensures elements like ref=\"asx:abap\" render as <asx:abap>\n if (element.ref) {\n const refName = stripNsPrefix(element.ref);\n const refElement = findElement(refName, schema);\n if (refElement) {\n return {\n tagName: element.ref, // Keep original ref with prefix for tag\n dataKey: refElement.element.name ?? refName, // Local name for data lookup\n typeName: refElement.element.type\n ? stripNsPrefix(refElement.element.type)\n : undefined,\n inlineComplexType: refElement.element.complexType as\n | ComplexTypeLike\n | undefined,\n elementSchema: refElement.schema,\n form: undefined, // Refs always use their prefix\n };\n }\n // Fallback: use ref as tag, local name for data\n return {\n tagName: element.ref,\n dataKey: refName,\n typeName: undefined,\n inlineComplexType: undefined,\n elementSchema: schema,\n form: undefined,\n };\n }\n\n return undefined;\n}\n\n/**\n * Build a field (child element)\n *\n * Respects elementFormDefault:\n * - \"qualified\": local elements get namespace prefix\n * - \"unqualified\" (default): local elements do NOT get namespace prefix\n */\nfunction buildField(\n doc: XmlDocument,\n parent: XmlElement,\n value: unknown,\n elementName: string,\n typeName: string | undefined,\n schema: SchemaLike,\n rootSchema: SchemaLike,\n prefix: string | undefined,\n): void {\n if (value === undefined || value === null) return;\n\n // Search for nested complexType\n const nestedType = typeName ? findComplexType(typeName, schema) : undefined;\n\n // Check elementFormDefault - local elements only get prefix when \"qualified\"\n // Default is \"unqualified\" per XSD spec\n const elementFormDefault = (rootSchema as { elementFormDefault?: string })\n .elementFormDefault;\n const usePrefix = elementFormDefault === 'qualified' ? prefix : undefined;\n const tagName = usePrefix ? `${usePrefix}:${elementName}` : elementName;\n\n if (Array.isArray(value)) {\n for (const item of value) {\n const child = doc.createElement(tagName);\n if (nestedType) {\n buildElement(\n doc,\n child,\n item as Record<string, unknown>,\n nestedType.ct,\n nestedType.schema,\n rootSchema,\n prefix,\n );\n } else {\n // Only add text node if value is not empty (allows self-closing tags)\n const text = formatValue(item, typeName || 'string');\n if (text) child.appendChild(doc.createTextNode(text));\n }\n parent.appendChild(child);\n }\n } else {\n const child = doc.createElement(tagName);\n if (nestedType) {\n buildElement(\n doc,\n child,\n value as Record<string, unknown>,\n nestedType.ct,\n nestedType.schema,\n rootSchema,\n prefix,\n );\n } else {\n // Only add text node if value is not empty (allows self-closing tags)\n const text = formatValue(value, typeName || 'string');\n if (text) child.appendChild(doc.createTextNode(text));\n }\n parent.appendChild(child);\n }\n}\n\n/**\n * Build a field with an explicit tag name (used for element refs with prefix)\n *\n * Handles three cases:\n * 1. Element refs with prefix (e.g., ref=\"asx:abap\") - use tagName directly\n * 2. Elements with form=\"unqualified\" - never use prefix\n * 3. Direct elements - apply elementFormDefault logic\n */\nfunction buildFieldWithTagName(\n doc: XmlDocument,\n parent: XmlElement,\n value: unknown,\n tagName: string,\n typeName: string | undefined,\n inlineComplexType: ComplexTypeLike | undefined,\n elementSchema: SchemaLike,\n rootSchema: SchemaLike,\n prefix: string | undefined,\n elementForm: string | undefined,\n): void {\n if (value === undefined || value === null) return;\n\n // First check for inline complexType, then search for named type\n let nestedType: { ct: ComplexTypeLike; schema: SchemaLike } | undefined;\n if (inlineComplexType) {\n nestedType = { ct: inlineComplexType, schema: elementSchema };\n } else if (typeName) {\n nestedType = findComplexType(typeName, elementSchema);\n }\n\n // Determine the actual tag name to use\n // Priority: 1. Per-element form attribute, 2. Schema elementFormDefault\n // If tagName already has a prefix (e.g., \"asx:abap\"), use it directly\n let actualTagName = tagName;\n if (!tagName.includes(':')) {\n // No prefix in tagName - check element form first, then schema default\n let usePrefix: string | undefined;\n if (elementForm === 'unqualified') {\n // Element explicitly marked as unqualified - no prefix\n usePrefix = undefined;\n } else if (elementForm === 'qualified') {\n // Element explicitly marked as qualified - use the element's defining schema prefix\n usePrefix = getPrefixForSchema(elementSchema, rootSchema) ?? prefix;\n } else {\n // No element-level form - use the element's defining schema's default first,\n // then fall back to root schema default. This ensures elements from imported\n // schemas (e.g., packageRef in adtcore:AdtMainObject) respect their own\n // schema's elementFormDefault and get the correct namespace prefix.\n const definingFormDefault = (\n elementSchema as { elementFormDefault?: string }\n ).elementFormDefault;\n const effectiveFormDefault =\n definingFormDefault ??\n (rootSchema as { elementFormDefault?: string }).elementFormDefault;\n // Use the element's defining schema prefix, not root prefix\n usePrefix =\n effectiveFormDefault === 'qualified'\n ? (getPrefixForSchema(elementSchema, rootSchema) ?? prefix)\n : undefined;\n }\n actualTagName = usePrefix ? `${usePrefix}:${tagName}` : tagName;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n const child = doc.createElement(actualTagName);\n if (nestedType) {\n buildElement(\n doc,\n child,\n item as Record<string, unknown>,\n nestedType.ct,\n nestedType.schema,\n rootSchema,\n prefix,\n );\n } else {\n // Only add text node if value is not empty (allows self-closing tags)\n const text = formatValue(item, typeName || 'string');\n if (text) child.appendChild(doc.createTextNode(text));\n }\n parent.appendChild(child);\n }\n } else {\n const child = doc.createElement(actualTagName);\n if (nestedType) {\n buildElement(\n doc,\n child,\n value as Record<string, unknown>,\n nestedType.ct,\n nestedType.schema,\n rootSchema,\n prefix,\n );\n } else {\n // Only add text node if value is not empty (allows self-closing tags)\n const text = formatValue(value, typeName || 'string');\n if (text) child.appendChild(doc.createTextNode(text));\n }\n parent.appendChild(child);\n }\n}\n\n/**\n * Find all elements that substitute for a given abstract element name.\n * Searches in the main schema and all $imports.\n */\nfunction findSubstitutes(\n abstractElementName: string,\n schema: SchemaLike,\n): Array<{ element: ElementLike; schema: SchemaLike }> {\n const substitutes: Array<{ element: ElementLike; schema: SchemaLike }> = [];\n\n // Helper to search in a single schema\n const searchSchema = (s: SchemaLike) => {\n const elements = s.element;\n if (!elements) return;\n\n for (const el of elements) {\n if (el.substitutionGroup) {\n const subGroupName = stripNsPrefix(el.substitutionGroup);\n if (subGroupName === abstractElementName) {\n substitutes.push({ element: el, schema: s });\n }\n }\n }\n };\n\n // Search in main schema\n searchSchema(schema);\n\n // Search in $imports\n const imports = schema.$imports as SchemaLike[] | undefined;\n if (imports) {\n for (const imported of imports) {\n searchSchema(imported);\n }\n }\n\n return substitutes;\n}\n","/**\n * Typed Schema Wrapper\n *\n * Wraps a raw schema literal with typed parse() and build() methods.\n * Enables full type inference from schema definitions.\n *\n * @example\n * ```typescript\n * import { typed } from '@abapify/ts-xsd';\n * import type { InferSchema } from '@abapify/ts-xsd';\n *\n * const rawSchema = { ... } as const;\n *\n * // Option 1: Infer type from schema\n * const schema = typed(rawSchema);\n * const data = schema.parse(xml); // InferSchema<typeof rawSchema>\n *\n * // Option 2: Explicit type (e.g., from generated interfaces)\n * import type { PersonType } from './types';\n * const schema = typed<PersonType>(rawSchema);\n * const data = schema.parse(xml); // PersonType\n * ```\n */\n\nimport type { SchemaLike, InferSchema } from '../infer';\nimport { parse } from './parse';\nimport { build, type BuildOptions } from './build';\n\n/**\n * Typed schema instance with parse/build methods\n */\nexport interface TypedSchema<T, S extends SchemaLike = SchemaLike> {\n /** The data type - use with typeof for type extraction */\n readonly _type: T;\n\n /** The underlying raw schema */\n readonly schema: S;\n\n /** Parse XML string to typed object */\n parse(xml: string): T;\n\n /** Build typed object to XML string */\n build(data: T, options?: BuildOptions): string;\n}\n\n/** Resolve data type: use explicit T if provided, otherwise infer from schema */\ntype ResolveDataType<T, S extends SchemaLike> = unknown extends T\n ? InferSchema<S>\n : T;\n\n/** Extract the data type from a TypedSchema */\nexport type InferTypedSchema<T extends TypedSchema<unknown>> = T['_type'];\n\n/**\n * Create a typed schema wrapper\n *\n * @param schema - Raw schema literal (with `as const`)\n * @returns Typed schema with parse/build methods\n *\n * @example\n * ```typescript\n * // Infer type from schema\n * const personSchema = typedSchema(rawPersonSchema);\n * const person = personSchema.parse(xml);\n *\n * // Or with explicit type\n * const personSchema = typedSchema<PersonType>(rawPersonSchema);\n * ```\n */\nexport function typedSchema<T = unknown, S extends SchemaLike = SchemaLike>(\n schema: S,\n): TypedSchema<ResolveDataType<T, S>, S> {\n type Data = ResolveDataType<T, S>;\n return {\n // Type-only property for type extraction (not used at runtime)\n _type: null as unknown as Data,\n schema,\n parse(xml: string): Data {\n return parse(schema, xml) as Data;\n },\n build(data: Data, options?: BuildOptions): string {\n return build(schema, data, options);\n },\n };\n}\n"],"mappings":"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"}