in packages/xml-parser-ts-codegen/src/codegen.ts [568:876]
function getMetaProperties(
__RELATIVE_LOCATION: string,
__META_TYPE_MAPPING: Map<string, XptcMetaType>,
__GLOBAL_ELEMENTS: Map<string, XptcElement>,
__SUBSTITUTIONS: Map<string, Map<string, string[]>>,
__XSDS: Map<string, XsdSchema>,
__NAMED_TYPES_BY_TS_NAME: Map<string, XptcComplexType | XptcSimpleType>,
ct: XptcComplexType,
metaTypeName: string
): { anonymousTypes: XptcMetaType[]; needsExtensionType: boolean; metaProperties: XptcMetaTypeProperty[] } {
/** Accumulates all properties of this complex type (ct). Attributes and elements. */
let ctMetaProperties: XptcMetaTypeProperty[] = [];
/** Accumulates all anonymous types instantiated on this complex type's hierarchy */
const anonymousTypes: XptcMetaType[] = [];
const immediateParentType = ct.childOf
? getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, ct.declaredAtRelativeLocation, ct.childOf)
: undefined;
let curParentCt = immediateParentType ? __NAMED_TYPES_BY_TS_NAME.get(immediateParentType.name) : undefined;
let needsExtensionType = ct.needsExtensionType;
while (curParentCt) {
const curParentCtMetaProperties: XptcMetaTypeProperty[] = [];
if (curParentCt?.type === "complex") {
const curParentCtMetaTypeName = getTsNameFromNamedType(
curParentCt.declaredAtRelativeLocation,
curParentCt.isAnonymous ? getAnonymousMetaTypeName(curParentCt.forElementWithName, "GLOBAL") : curParentCt.name
);
needsExtensionType = needsExtensionType || curParentCt.needsExtensionType;
if (curParentCt.isAnonymous) {
throw new Error("Anonymous types are never parent types.");
}
for (const a of curParentCt.attributes) {
const attributeType = getTsTypeFromLocalRef(
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
curParentCt.declaredAtRelativeLocation,
a.localTypeRef
);
if (!attributeType) {
throw new Error(`Can't resolve local type ref ${a.localTypeRef}`);
}
curParentCtMetaProperties.push({
declaredAt: curParentCt.declaredAtRelativeLocation,
fromType: curParentCtMetaTypeName,
elem: undefined,
name: `@_${a.name}`,
metaType: { name: getMetaTypeName(attributeType), xsdType: attributeType.annotation },
isArray: false,
isOptional: a.isOptional,
});
}
for (const e of curParentCt.elements) {
if (e.kind === "ofAnonymousType") {
const anonymousTypeName = getAnonymousMetaTypeName(e.name, metaTypeName);
const mp = getMetaProperties(
__RELATIVE_LOCATION,
__META_TYPE_MAPPING,
__GLOBAL_ELEMENTS,
__SUBSTITUTIONS,
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
e.anonymousType,
anonymousTypeName
);
anonymousTypes.push({ name: anonymousTypeName, properties: mp.metaProperties });
anonymousTypes.push(...mp.anonymousTypes);
__META_TYPE_MAPPING.set(anonymousTypeName, {
name: anonymousTypeName,
properties: mp.metaProperties,
});
curParentCtMetaProperties.push({
elem: undefined, // REALLY?
declaredAt: curParentCt.declaredAtRelativeLocation,
fromType: curParentCtMetaTypeName,
name: e.name,
metaType: { name: anonymousTypeName, xsdType: "Anonumous type..." },
isArray: e.isArray,
isOptional: e.isOptional,
});
} else if (e.kind === "ofNamedType") {
const tsType = getTsTypeFromLocalRef(
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation,
e.typeName
);
curParentCtMetaProperties.push({
declaredAt: curParentCt.declaredAtRelativeLocation,
fromType: curParentCtMetaTypeName,
elem: undefined, // REALLY?
name: e.name,
metaType: { name: getMetaTypeName(tsType), xsdType: tsType.annotation },
typeBody: getTsTypeBody(tsType),
isArray: e.isArray,
isOptional: e.isOptional,
});
} else if (e.kind === "ofRef") {
const referencedElement = getXptcElementFromLocalElementRef(
__XSDS,
__GLOBAL_ELEMENTS,
ct.declaredAtRelativeLocation,
e.ref
);
if (!referencedElement) {
throw new Error(`Can't find reference to element '${e.ref}'`);
}
const tsType = referencedElement.type
? getTsTypeFromLocalRef(
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation,
referencedElement.type
)
: {
name: getTsNameFromNamedType(
ct.declaredAtRelativeLocation,
getAnonymousMetaTypeName(referencedElement.name, "GLOBAL")
),
annotation: "Anonymous type from element " + referencedElement.name,
};
curParentCtMetaProperties.push({
declaredAt: referencedElement?.declaredAtRelativeLocation,
fromType: ct.isAnonymous ? "" : curParentCtMetaTypeName,
name: referencedElement.name,
elem: referencedElement,
metaType: { name: getMetaTypeName(tsType), xsdType: tsType.annotation },
typeBody: () =>
getTypeBodyForElementRef(
__RELATIVE_LOCATION,
__META_TYPE_MAPPING,
__GLOBAL_ELEMENTS,
__SUBSTITUTIONS,
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
ct,
referencedElement
),
isArray: e.isArray,
isOptional: e.isOptional,
});
} else {
throw new Error("Unknonwn type of element " + e);
}
}
const nextParentType = curParentCt.childOf
? getTsTypeFromLocalRef(
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
curParentCt.declaredAtRelativeLocation,
curParentCt.childOf
)
: undefined;
// Make sure the inheritance order is respected. Elements should be listed always from the most generic to the most specific type.
// Since we're iterating upwards in the hierarchy, we need to invert prepend the array with the props we find on each step of the hierarchy.
ctMetaProperties = [...curParentCtMetaProperties, ...ctMetaProperties];
curParentCt = nextParentType ? __NAMED_TYPES_BY_TS_NAME.get(nextParentType.name) : undefined;
} else if (curParentCt?.type === "simple") {
throw new Error("Can't have a non-complex type as parent of another.");
} else {
curParentCt = undefined;
}
}
// Own properties are parsed later to ensure xsd:sequence order.
for (const a of ct.attributes) {
const attributeType = getTsTypeFromLocalRef(
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation,
a.localTypeRef
);
ctMetaProperties.push({
declaredAt: ct.declaredAtRelativeLocation,
fromType: metaTypeName,
name: `@_${a.name}`,
elem: undefined,
metaType: { name: getMetaTypeName(attributeType), xsdType: attributeType.annotation },
isArray: false,
isOptional: a.isOptional,
});
}
for (const e of ct.elements) {
if (e.kind === "ofRef") {
const referencedElement = getXptcElementFromLocalElementRef(
__XSDS,
__GLOBAL_ELEMENTS,
ct.declaredAtRelativeLocation,
e.ref
);
if (!referencedElement) {
throw new Error(`Can't find reference to element '${e.ref}'`);
}
const tsType = referencedElement.type
? getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, ct.declaredAtRelativeLocation, referencedElement.type)
: {
name: getTsNameFromNamedType(
ct.declaredAtRelativeLocation,
getAnonymousMetaTypeName(referencedElement.name, "GLOBAL")
),
annotation: "Anonymous type from element " + referencedElement.name,
};
ctMetaProperties.push({
declaredAt: referencedElement?.declaredAtRelativeLocation,
fromType: ct.isAnonymous ? "" : metaTypeName,
name: referencedElement.name,
elem: referencedElement,
metaType: { name: getMetaTypeName(tsType), xsdType: tsType.annotation },
typeBody: () =>
getTypeBodyForElementRef(
__RELATIVE_LOCATION,
__META_TYPE_MAPPING,
__GLOBAL_ELEMENTS,
__SUBSTITUTIONS,
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
ct,
referencedElement
),
isArray: e.isArray,
isOptional: e.isOptional,
});
} else if (e.kind === "ofNamedType") {
const tsType = getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, ct.declaredAtRelativeLocation, e.typeName);
ctMetaProperties.push({
declaredAt: ct.declaredAtRelativeLocation,
fromType: metaTypeName,
name: e.name,
elem: undefined, // REALLY?
metaType: { name: getMetaTypeName(tsType), xsdType: tsType.annotation },
typeBody: getTsTypeBody(tsType),
isArray: e.isArray,
isOptional: e.isOptional,
});
} else if (e.kind === "ofAnonymousType") {
const anonymousTypeName = getAnonymousMetaTypeName(e.name, metaTypeName);
const mp = getMetaProperties(
__RELATIVE_LOCATION,
__META_TYPE_MAPPING,
__GLOBAL_ELEMENTS,
__SUBSTITUTIONS,
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
e.anonymousType,
anonymousTypeName
);
anonymousTypes.push({ name: anonymousTypeName, properties: mp.metaProperties });
anonymousTypes.push(...mp.anonymousTypes);
__META_TYPE_MAPPING.set(anonymousTypeName, {
name: anonymousTypeName,
properties: mp.metaProperties,
});
ctMetaProperties.push({
declaredAt: ct.declaredAtRelativeLocation,
fromType: metaTypeName,
name: e.name,
elem: undefined, // REALLY?
metaType: { name: anonymousTypeName, xsdType: "Anonymous type..." },
isArray: e.isArray,
isOptional: e.isOptional,
});
} else {
throw new Error(`Unknown kind of XptcComplexType '${e}'`);
}
}
if (ct.isSimpleContent && ct.childOf) {
const t = getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, ct.declaredAtRelativeLocation, ct.childOf);
ctMetaProperties.push({
declaredAt: ct.declaredAtRelativeLocation,
fromType: metaTypeName,
name: `__$$text`,
elem: undefined,
metaType: {
name: t.name,
xsdType: t.annotation,
},
isArray: false,
isOptional: false,
});
}
if (!(ct.type === "complex" && !ct.isAnonymous && ct.isAbstract)) {
__META_TYPE_MAPPING.set(metaTypeName, {
name: metaTypeName,
properties: [...ctMetaProperties.reduce((acc, p) => acc.set(p.name, p), new Map()).values()], // Removing duplicates.
});
}
return { metaProperties: ctMetaProperties, needsExtensionType, anonymousTypes };
}