@cerios/xml-poto-codegen
Advanced tools
+41
-7
@@ -8,4 +8,8 @@ /** | ||
| xsdPath: string; | ||
| /** Output directory for generated TypeScript files. */ | ||
| outputDir: string; | ||
| /** | ||
| * Output path for generated TypeScript files. | ||
| * - per-type: directory path | ||
| * - per-xsd: file path | ||
| */ | ||
| outputPath: string; | ||
| /** Output style: 'per-type' generates one file per class, 'per-xsd' puts all types in one file. */ | ||
@@ -19,3 +23,3 @@ outputStyle?: "per-type" | "per-xsd"; | ||
| */ | ||
| interface CodegenConfig { | ||
| interface XmlPotoCodegenConfig { | ||
| /** Array of XSD sources to process. */ | ||
@@ -29,6 +33,6 @@ sources: XsdSource[]; | ||
| declare function validateConfig(config: unknown): CodegenConfig; | ||
| declare function validateConfig(config: unknown): XmlPotoCodegenConfig; | ||
| declare function findConfigFile(cwd: string): string | undefined; | ||
| declare function loadConfig(configPath?: string): Promise<{ | ||
| config: CodegenConfig; | ||
| config: XmlPotoCodegenConfig; | ||
| configDir: string; | ||
@@ -159,2 +163,11 @@ }>; | ||
| pattern?: string; | ||
| minLength?: number; | ||
| maxLength?: number; | ||
| minInclusive?: number; | ||
| maxInclusive?: number; | ||
| minExclusive?: number; | ||
| maxExclusive?: number; | ||
| totalDigits?: number; | ||
| fractionDigits?: number; | ||
| whiteSpace?: "preserve" | "replace" | "collapse"; | ||
| attributes: XsdAttribute[]; | ||
@@ -244,2 +257,4 @@ } | ||
| hasSimpleContent?: boolean; | ||
| /** Root-level nillable flag when promoted from top-level element reference */ | ||
| rootNillable?: boolean; | ||
| } | ||
@@ -289,2 +304,14 @@ type PropertyKind = "element" | "attribute" | "text" | "array" | "dynamic"; | ||
| dataType?: string; | ||
| /** XSD fixed value constraint */ | ||
| fixedValue?: string; | ||
| /** XSD restriction facets retained for diagnostics/manual post-processing */ | ||
| minLength?: number; | ||
| maxLength?: number; | ||
| minInclusive?: number; | ||
| maxInclusive?: number; | ||
| minExclusive?: number; | ||
| maxExclusive?: number; | ||
| totalDigits?: number; | ||
| fractionDigits?: number; | ||
| whiteSpace?: "preserve" | "replace" | "collapse"; | ||
| } | ||
@@ -334,2 +361,4 @@ interface ResolvedEnum { | ||
| private resolveElementForm; | ||
| private resolveAttributeForm; | ||
| private resolveNamespaceForForm; | ||
| private findPrefixForUri; | ||
@@ -380,2 +409,3 @@ private buildDefaultInitializer; | ||
| private collectLocalImports; | ||
| private applyRootElements; | ||
| } | ||
@@ -399,2 +429,6 @@ | ||
| }; | ||
| /** | ||
| * Writes one generated file to an explicit output file path. | ||
| */ | ||
| declare function writeGeneratedFile(outputFilePath: string, file: GeneratedFile): string; | ||
@@ -406,3 +440,3 @@ /** Build an import statement */ | ||
| /** Build a class property declaration line */ | ||
| declare function buildProperty(name: string, type: string, initializer: string, optional?: boolean): string; | ||
| declare function buildProperty(name: string, type: string, initializer?: string, optional?: boolean): string; | ||
| /** Build the auto-generated file header */ | ||
@@ -467,2 +501,2 @@ declare function buildFileHeader(xsdPath: string): string; | ||
| export { ClassGenerator, type CodegenConfig, type EnumStyle, type GeneratedFile, type ResolvedEnum, type ResolvedProperty, type ResolvedRootElement, type ResolvedSchema, type ResolvedType, type XsdAll, type XsdAny, type XsdAttribute, type XsdAttributeGroup, type XsdAttributeGroupRef, type XsdChoice, type XsdComplexContent, type XsdComplexContentExtension, type XsdComplexContentRestriction, type XsdComplexType, type XsdElement, type XsdGroup, type XsdGroupRef, type XsdImport, type XsdInclude, type XsdNamespace, XsdParser, XsdResolver, type XsdRestriction, type XsdSchema, type XsdSequence, type XsdSimpleContent, type XsdSimpleContentExtension, type XsdSimpleContentRestriction, type XsdSimpleType, type XsdSource, buildDecorator, buildFileHeader, buildImport, buildProperty, collectImports, findConfigFile, loadConfig, mapClassDecorator, mapPropertyDecorator, toCamelCase, toKebabCase, toPascalCase, validateConfig, writeGeneratedFiles }; | ||
| export { ClassGenerator, type EnumStyle, type GeneratedFile, type ResolvedEnum, type ResolvedProperty, type ResolvedRootElement, type ResolvedSchema, type ResolvedType, type XmlPotoCodegenConfig, type XsdAll, type XsdAny, type XsdAttribute, type XsdAttributeGroup, type XsdAttributeGroupRef, type XsdChoice, type XsdComplexContent, type XsdComplexContentExtension, type XsdComplexContentRestriction, type XsdComplexType, type XsdElement, type XsdGroup, type XsdGroupRef, type XsdImport, type XsdInclude, type XsdNamespace, XsdParser, XsdResolver, type XsdRestriction, type XsdSchema, type XsdSequence, type XsdSimpleContent, type XsdSimpleContentExtension, type XsdSimpleContentRestriction, type XsdSimpleType, type XsdSource, buildDecorator, buildFileHeader, buildImport, buildProperty, collectImports, findConfigFile, loadConfig, mapClassDecorator, mapPropertyDecorator, toCamelCase, toKebabCase, toPascalCase, validateConfig, writeGeneratedFile, writeGeneratedFiles }; |
+41
-7
@@ -8,4 +8,8 @@ /** | ||
| xsdPath: string; | ||
| /** Output directory for generated TypeScript files. */ | ||
| outputDir: string; | ||
| /** | ||
| * Output path for generated TypeScript files. | ||
| * - per-type: directory path | ||
| * - per-xsd: file path | ||
| */ | ||
| outputPath: string; | ||
| /** Output style: 'per-type' generates one file per class, 'per-xsd' puts all types in one file. */ | ||
@@ -19,3 +23,3 @@ outputStyle?: "per-type" | "per-xsd"; | ||
| */ | ||
| interface CodegenConfig { | ||
| interface XmlPotoCodegenConfig { | ||
| /** Array of XSD sources to process. */ | ||
@@ -29,6 +33,6 @@ sources: XsdSource[]; | ||
| declare function validateConfig(config: unknown): CodegenConfig; | ||
| declare function validateConfig(config: unknown): XmlPotoCodegenConfig; | ||
| declare function findConfigFile(cwd: string): string | undefined; | ||
| declare function loadConfig(configPath?: string): Promise<{ | ||
| config: CodegenConfig; | ||
| config: XmlPotoCodegenConfig; | ||
| configDir: string; | ||
@@ -159,2 +163,11 @@ }>; | ||
| pattern?: string; | ||
| minLength?: number; | ||
| maxLength?: number; | ||
| minInclusive?: number; | ||
| maxInclusive?: number; | ||
| minExclusive?: number; | ||
| maxExclusive?: number; | ||
| totalDigits?: number; | ||
| fractionDigits?: number; | ||
| whiteSpace?: "preserve" | "replace" | "collapse"; | ||
| attributes: XsdAttribute[]; | ||
@@ -244,2 +257,4 @@ } | ||
| hasSimpleContent?: boolean; | ||
| /** Root-level nillable flag when promoted from top-level element reference */ | ||
| rootNillable?: boolean; | ||
| } | ||
@@ -289,2 +304,14 @@ type PropertyKind = "element" | "attribute" | "text" | "array" | "dynamic"; | ||
| dataType?: string; | ||
| /** XSD fixed value constraint */ | ||
| fixedValue?: string; | ||
| /** XSD restriction facets retained for diagnostics/manual post-processing */ | ||
| minLength?: number; | ||
| maxLength?: number; | ||
| minInclusive?: number; | ||
| maxInclusive?: number; | ||
| minExclusive?: number; | ||
| maxExclusive?: number; | ||
| totalDigits?: number; | ||
| fractionDigits?: number; | ||
| whiteSpace?: "preserve" | "replace" | "collapse"; | ||
| } | ||
@@ -334,2 +361,4 @@ interface ResolvedEnum { | ||
| private resolveElementForm; | ||
| private resolveAttributeForm; | ||
| private resolveNamespaceForForm; | ||
| private findPrefixForUri; | ||
@@ -380,2 +409,3 @@ private buildDefaultInitializer; | ||
| private collectLocalImports; | ||
| private applyRootElements; | ||
| } | ||
@@ -399,2 +429,6 @@ | ||
| }; | ||
| /** | ||
| * Writes one generated file to an explicit output file path. | ||
| */ | ||
| declare function writeGeneratedFile(outputFilePath: string, file: GeneratedFile): string; | ||
@@ -406,3 +440,3 @@ /** Build an import statement */ | ||
| /** Build a class property declaration line */ | ||
| declare function buildProperty(name: string, type: string, initializer: string, optional?: boolean): string; | ||
| declare function buildProperty(name: string, type: string, initializer?: string, optional?: boolean): string; | ||
| /** Build the auto-generated file header */ | ||
@@ -467,2 +501,2 @@ declare function buildFileHeader(xsdPath: string): string; | ||
| export { ClassGenerator, type CodegenConfig, type EnumStyle, type GeneratedFile, type ResolvedEnum, type ResolvedProperty, type ResolvedRootElement, type ResolvedSchema, type ResolvedType, type XsdAll, type XsdAny, type XsdAttribute, type XsdAttributeGroup, type XsdAttributeGroupRef, type XsdChoice, type XsdComplexContent, type XsdComplexContentExtension, type XsdComplexContentRestriction, type XsdComplexType, type XsdElement, type XsdGroup, type XsdGroupRef, type XsdImport, type XsdInclude, type XsdNamespace, XsdParser, XsdResolver, type XsdRestriction, type XsdSchema, type XsdSequence, type XsdSimpleContent, type XsdSimpleContentExtension, type XsdSimpleContentRestriction, type XsdSimpleType, type XsdSource, buildDecorator, buildFileHeader, buildImport, buildProperty, collectImports, findConfigFile, loadConfig, mapClassDecorator, mapPropertyDecorator, toCamelCase, toKebabCase, toPascalCase, validateConfig, writeGeneratedFiles }; | ||
| export { ClassGenerator, type EnumStyle, type GeneratedFile, type ResolvedEnum, type ResolvedProperty, type ResolvedRootElement, type ResolvedSchema, type ResolvedType, type XmlPotoCodegenConfig, type XsdAll, type XsdAny, type XsdAttribute, type XsdAttributeGroup, type XsdAttributeGroupRef, type XsdChoice, type XsdComplexContent, type XsdComplexContentExtension, type XsdComplexContentRestriction, type XsdComplexType, type XsdElement, type XsdGroup, type XsdGroupRef, type XsdImport, type XsdInclude, type XsdNamespace, XsdParser, XsdResolver, type XsdRestriction, type XsdSchema, type XsdSequence, type XsdSimpleContent, type XsdSimpleContentExtension, type XsdSimpleContentRestriction, type XsdSimpleType, type XsdSource, buildDecorator, buildFileHeader, buildImport, buildProperty, collectImports, findConfigFile, loadConfig, mapClassDecorator, mapPropertyDecorator, toCamelCase, toKebabCase, toPascalCase, validateConfig, writeGeneratedFile, writeGeneratedFiles }; |
+302
-47
@@ -49,2 +49,3 @@ "use strict"; | ||
| validateConfig: () => validateConfig, | ||
| writeGeneratedFile: () => writeGeneratedFile, | ||
| writeGeneratedFiles: () => writeGeneratedFiles | ||
@@ -57,3 +58,3 @@ }); | ||
| var import_node_path = __toESM(require("path")); | ||
| var import_node_url = require("url"); | ||
| var import_jiti = require("jiti"); | ||
| var CONFIG_NAMES = ["xml-poto-codegen.config.ts", "xml-poto-codegen.config.json"]; | ||
@@ -87,4 +88,4 @@ function validateConfig(config) { | ||
| } | ||
| if (!src.outputDir || typeof src.outputDir !== "string") { | ||
| throw new Error(`sources[${index}].outputDir must be a non-empty string.`); | ||
| if (!src.outputPath || typeof src.outputPath !== "string") { | ||
| throw new Error(`sources[${index}].outputPath must be a non-empty string.`); | ||
| } | ||
@@ -114,3 +115,2 @@ if (!isValidOutputStyle(src.outputStyle)) { | ||
| async function loadConfig(configPath) { | ||
| var _a; | ||
| const resolvedPath = configPath ? import_node_path.default.resolve(configPath) : findConfigFile(process.cwd()); | ||
@@ -129,5 +129,9 @@ if (!resolvedPath) { | ||
| } else if (resolvedPath.endsWith(".ts")) { | ||
| const fileUrl = (0, import_node_url.pathToFileURL)(resolvedPath).href; | ||
| const mod = await import(fileUrl); | ||
| raw = (_a = mod.default) != null ? _a : mod; | ||
| const jiti = (0, import_jiti.createJiti)(__filename); | ||
| const mod = await jiti.import(resolvedPath, { default: true }); | ||
| if (mod && typeof mod === "object" && "default" in mod) { | ||
| raw = mod.default; | ||
| } else { | ||
| raw = mod; | ||
| } | ||
| } else { | ||
@@ -186,2 +190,5 @@ throw new Error(`Unsupported config file format: ${resolvedPath}`); | ||
| const optionalMark = optional ? "?" : ""; | ||
| if (initializer === void 0) { | ||
| return `${name}${optionalMark}: ${type};`; | ||
| } | ||
| return `${name}${optionalMark}: ${type} = ${initializer};`; | ||
@@ -206,9 +213,16 @@ } | ||
| if (type.isRootElement) { | ||
| const opts = { name: `'${type.xmlName}'` }; | ||
| const opts2 = { name: `'${type.xmlName}'` }; | ||
| if (type.namespace) { | ||
| opts.namespace = buildNamespaceObj(type.namespace); | ||
| opts2.namespace = buildNamespaceObj(type.namespace); | ||
| } | ||
| return buildDecorator("XmlRoot", opts); | ||
| if (type.rootNillable) { | ||
| opts2.isNullable = true; | ||
| } | ||
| return buildDecorator("XmlRoot", opts2); | ||
| } | ||
| return buildDecorator("XmlElement", { name: `'${type.xmlName}'` }); | ||
| const opts = { name: `'${type.xmlName}'` }; | ||
| if (type.namespace) { | ||
| opts.namespace = buildNamespaceObj(type.namespace); | ||
| } | ||
| return buildDecorator("XmlElement", opts); | ||
| } | ||
@@ -250,2 +264,3 @@ function mapPropertyDecorator(prop) { | ||
| imports.add("XmlDynamic"); | ||
| imports.add("DynamicElement"); | ||
| break; | ||
@@ -263,2 +278,3 @@ } | ||
| if (prop.form) opts.form = `'${prop.form}'`; | ||
| if (prop.namespace) opts.namespace = buildNamespaceObj(prop.namespace); | ||
| if (prop.defaultValue !== void 0) opts.defaultValue = formatDefault(prop.tsType, prop.defaultValue); | ||
@@ -275,4 +291,5 @@ if (prop.complexTypeName) opts.type = prop.complexTypeName; | ||
| if (prop.defaultValue !== void 0) opts.defaultValue = formatDefault(prop.tsType, prop.defaultValue); | ||
| if (prop.enumValues && prop.enumValues.length > 0) opts.enumValues = prop.enumValues.map((v) => `'${v}'`); | ||
| if (prop.pattern) opts.pattern = `/${prop.pattern}/`; | ||
| if (prop.enumValues && prop.enumValues.length > 0) | ||
| opts.enumValues = prop.enumValues.map((v) => `'${escapeString(v)}'`); | ||
| if (prop.pattern) opts.pattern = `new RegExp(${JSON.stringify(prop.pattern)})`; | ||
| if (prop.dataType) opts.dataType = `'${prop.dataType}'`; | ||
@@ -295,2 +312,3 @@ if (prop.namespace) opts.namespace = buildNamespaceObj(prop.namespace); | ||
| if (prop.isNullable) opts.isNullable = true; | ||
| if (prop.namespace) opts.namespace = buildNamespaceObj(prop.namespace); | ||
| if (prop.dataType) opts.dataType = `'${prop.dataType}'`; | ||
@@ -301,2 +319,3 @@ return buildDecorator("XmlArray", opts); | ||
| const opts = {}; | ||
| if (prop.required) opts.required = true; | ||
| if (prop.order !== void 0) opts.order = prop.order; | ||
@@ -314,4 +333,7 @@ return buildDecorator("XmlDynamic", opts); | ||
| if (tsType === "boolean") return value === "true" ? "true" : "false"; | ||
| return `'${value}'`; | ||
| return `'${escapeString(value)}'`; | ||
| } | ||
| function escapeString(value) { | ||
| return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'"); | ||
| } | ||
@@ -331,7 +353,8 @@ // src/generator/class-generator.ts | ||
| const files = []; | ||
| const resolvedTypes = this.applyRootElements(schema.types, schema.rootElements); | ||
| for (const enumDef of schema.enums) { | ||
| files.push(this.generateEnumFile(enumDef)); | ||
| } | ||
| for (const type of schema.types) { | ||
| files.push(this.generateClassFile(type, schema.types, schema.enums)); | ||
| for (const type of resolvedTypes) { | ||
| files.push(this.generateClassFile(type, resolvedTypes, schema.enums)); | ||
| } | ||
@@ -394,3 +417,4 @@ if (files.length > 0) { | ||
| const parts = [buildFileHeader(this.xsdPath)]; | ||
| for (const type of schema.types) { | ||
| const resolvedTypes = this.applyRootElements(schema.types, schema.rootElements); | ||
| for (const type of resolvedTypes) { | ||
| for (const imp of collectImports(type)) { | ||
@@ -400,3 +424,3 @@ allImports.add(imp); | ||
| } | ||
| const needsDynamic = schema.types.some((t) => t.properties.some((p) => p.kind === "dynamic")); | ||
| const needsDynamic = resolvedTypes.some((t) => t.properties.some((p) => p.kind === "dynamic")); | ||
| if (needsDynamic) { | ||
@@ -412,3 +436,3 @@ allImports.add("DynamicElement"); | ||
| } | ||
| for (const type of schema.types) { | ||
| for (const type of resolvedTypes) { | ||
| parts.push(this.generateClassSource(type)); | ||
@@ -468,4 +492,6 @@ parts.push(""); | ||
| const decorator = mapPropertyDecorator(prop); | ||
| const isOptional = prop.required !== true; | ||
| const initializer = isOptional ? void 0 : prop.initializer; | ||
| lines.push(` ${decorator}`); | ||
| lines.push(` ${buildProperty(prop.propertyName, prop.tsType, prop.initializer)}`); | ||
| lines.push(` ${buildProperty(prop.propertyName, prop.tsType, initializer, isOptional)}`); | ||
| lines.push(""); | ||
@@ -501,2 +527,32 @@ } | ||
| } | ||
| applyRootElements(types, rootElements) { | ||
| if (rootElements.length === 0) { | ||
| return types; | ||
| } | ||
| const rootMap = /* @__PURE__ */ new Map(); | ||
| for (const root of rootElements) { | ||
| const entries = rootMap.get(root.typeName); | ||
| if (entries) { | ||
| entries.push(root); | ||
| } else { | ||
| rootMap.set(root.typeName, [root]); | ||
| } | ||
| } | ||
| return types.map((type) => { | ||
| if (type.isRootElement) { | ||
| return type; | ||
| } | ||
| const roots = rootMap.get(type.className); | ||
| if (!roots || roots.length === 0) { | ||
| return type; | ||
| } | ||
| const root = roots[0]; | ||
| return { | ||
| ...type, | ||
| isRootElement: true, | ||
| xmlName: root.name, | ||
| rootNillable: root.nillable | ||
| }; | ||
| }); | ||
| } | ||
| }; | ||
@@ -508,3 +564,17 @@ function toEnumKey(value) { | ||
| } | ||
| return key.split("_").filter(Boolean).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(""); | ||
| const hadLeadingUnderscore = key.startsWith("_"); | ||
| let result = key.split("_").filter(Boolean).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(""); | ||
| if (hadLeadingUnderscore && !result.startsWith("_")) { | ||
| result = `_${result}`; | ||
| } | ||
| if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(result)) { | ||
| result = result.replace(/^[^A-Za-z_]+/, ""); | ||
| if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(result)) { | ||
| result = `_${result}`; | ||
| } | ||
| if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(result)) { | ||
| result = "_Value"; | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
@@ -525,2 +595,8 @@ | ||
| } | ||
| function writeGeneratedFile(outputFilePath, file) { | ||
| const parentDir = import_node_path2.default.dirname(outputFilePath); | ||
| import_node_fs2.default.mkdirSync(parentDir, { recursive: true }); | ||
| import_node_fs2.default.writeFileSync(outputFilePath, file.content, "utf-8"); | ||
| return outputFilePath; | ||
| } | ||
@@ -805,3 +881,3 @@ // src/xsd/xsd-parser.ts | ||
| parseSimpleContentRestriction(obj) { | ||
| var _a, _b; | ||
| var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k; | ||
| return { | ||
@@ -814,2 +890,11 @@ base: (_a = attr(obj, "base")) != null ? _a : "", | ||
| pattern: attr((_b = this.getChild(obj, this.xsd("pattern"))) != null ? _b : {}, "value"), | ||
| minLength: numAttr((_c = this.getChild(obj, this.xsd("minLength"))) != null ? _c : {}, "value"), | ||
| maxLength: numAttr((_d = this.getChild(obj, this.xsd("maxLength"))) != null ? _d : {}, "value"), | ||
| minInclusive: numAttr((_e = this.getChild(obj, this.xsd("minInclusive"))) != null ? _e : {}, "value"), | ||
| maxInclusive: numAttr((_f = this.getChild(obj, this.xsd("maxInclusive"))) != null ? _f : {}, "value"), | ||
| minExclusive: numAttr((_g = this.getChild(obj, this.xsd("minExclusive"))) != null ? _g : {}, "value"), | ||
| maxExclusive: numAttr((_h = this.getChild(obj, this.xsd("maxExclusive"))) != null ? _h : {}, "value"), | ||
| totalDigits: numAttr((_i = this.getChild(obj, this.xsd("totalDigits"))) != null ? _i : {}, "value"), | ||
| fractionDigits: numAttr((_j = this.getChild(obj, this.xsd("fractionDigits"))) != null ? _j : {}, "value"), | ||
| whiteSpace: attr((_k = this.getChild(obj, this.xsd("whiteSpace"))) != null ? _k : {}, "value"), | ||
| attributes: this.parseChildren(obj, this.xsd("attribute")).map((a) => this.parseAttribute(a)) | ||
@@ -1098,12 +1183,34 @@ }; | ||
| buildAttributeGroupLookups() { | ||
| const groupDefs = /* @__PURE__ */ new Map(); | ||
| for (const ag of this.schema.attributeGroups) { | ||
| if (ag.name) { | ||
| const attrs = [...ag.attributes]; | ||
| for (const ref of ag.attributeGroupRefs) { | ||
| const refName = stripPrefix(ref.ref); | ||
| const resolved = this.attributeGroupMap.get(refName); | ||
| if (resolved) attrs.push(...resolved); | ||
| groupDefs.set(ag.name, ag); | ||
| } | ||
| } | ||
| const resolving = /* @__PURE__ */ new Set(); | ||
| const resolveGroup = (name) => { | ||
| const cached = this.attributeGroupMap.get(name); | ||
| if (cached) return cached; | ||
| const def = groupDefs.get(name); | ||
| if (!def) { | ||
| return []; | ||
| } | ||
| if (resolving.has(name)) { | ||
| return []; | ||
| } | ||
| resolving.add(name); | ||
| const attrs = [...def.attributes]; | ||
| for (const ref of def.attributeGroupRefs) { | ||
| const refName = stripPrefix(ref.ref); | ||
| const resolvedAttrs = resolveGroup(refName); | ||
| if (resolvedAttrs.length) { | ||
| attrs.push(...resolvedAttrs); | ||
| } | ||
| this.attributeGroupMap.set(ag.name, attrs); | ||
| } | ||
| resolving.delete(name); | ||
| this.attributeGroupMap.set(name, attrs); | ||
| return attrs; | ||
| }; | ||
| for (const name of groupDefs.keys()) { | ||
| resolveGroup(name); | ||
| } | ||
@@ -1148,3 +1255,3 @@ } | ||
| } | ||
| let order = 0; | ||
| let order = 1; | ||
| if (ct.sequence) { | ||
@@ -1201,2 +1308,11 @@ order = this.resolveSequenceProperties(ct.sequence, resolved.properties, order); | ||
| pattern: sc.restriction.pattern, | ||
| minLength: sc.restriction.minLength, | ||
| maxLength: sc.restriction.maxLength, | ||
| minInclusive: sc.restriction.minInclusive, | ||
| maxInclusive: sc.restriction.maxInclusive, | ||
| minExclusive: sc.restriction.minExclusive, | ||
| maxExclusive: sc.restriction.maxExclusive, | ||
| totalDigits: sc.restriction.totalDigits, | ||
| fractionDigits: sc.restriction.fractionDigits, | ||
| whiteSpace: sc.restriction.whiteSpace, | ||
| dataType: baseInfo.dataType | ||
@@ -1210,3 +1326,3 @@ }); | ||
| resolved.baseTypeName = toPascalCase(stripPrefix(cc.extension.base)); | ||
| let order = 0; | ||
| let order = 1; | ||
| if (cc.extension.sequence) { | ||
@@ -1233,3 +1349,3 @@ order = this.resolveSequenceProperties(cc.extension.sequence, resolved.properties, order); | ||
| if (cc.restriction.sequence) { | ||
| this.resolveSequenceProperties(cc.restriction.sequence, resolved.properties, 0); | ||
| this.resolveSequenceProperties(cc.restriction.sequence, resolved.properties, 1); | ||
| } | ||
@@ -1262,3 +1378,3 @@ this.resolveAttributes(cc.restriction.attributes, resolved.properties); | ||
| }); | ||
| if (any.minOccurs !== void 0 && any.minOccurs > 0) { | ||
| if (any.minOccurs === void 0 || any.minOccurs > 0) { | ||
| props[props.length - 1].required = true; | ||
@@ -1305,5 +1421,6 @@ } | ||
| resolveElementProperty(el, order) { | ||
| var _a; | ||
| var _a, _b; | ||
| const isArray = el.maxOccurs === "unbounded" || typeof el.maxOccurs === "number" && el.maxOccurs > 1; | ||
| const isRequired = el.minOccurs === void 0 || el.minOccurs > 0; | ||
| const form = (_a = el.form) != null ? _a : this.resolveElementForm(); | ||
| const name = el.ref ? stripPrefix(el.ref) : el.name; | ||
@@ -1346,4 +1463,6 @@ if (this.substitutionMap.has(name)) { | ||
| isNullable: el.nillable, | ||
| form: (_a = el.form) != null ? _a : this.resolveElementForm(), | ||
| defaultValue: el.defaultValue, | ||
| form, | ||
| namespace: this.resolveNamespaceForForm(form), | ||
| defaultValue: (_b = el.defaultValue) != null ? _b : el.fixed, | ||
| fixedValue: el.fixed, | ||
| complexTypeName: typeInfo.complexTypeName, | ||
@@ -1353,3 +1472,12 @@ enumValues: typeInfo.enumValues, | ||
| enumTypeName: typeInfo.enumTypeName, | ||
| dataType: typeInfo.dataType | ||
| dataType: typeInfo.dataType, | ||
| minLength: typeInfo.minLength, | ||
| maxLength: typeInfo.maxLength, | ||
| minInclusive: typeInfo.minInclusive, | ||
| maxInclusive: typeInfo.maxInclusive, | ||
| minExclusive: typeInfo.minExclusive, | ||
| maxExclusive: typeInfo.maxExclusive, | ||
| totalDigits: typeInfo.totalDigits, | ||
| fractionDigits: typeInfo.fractionDigits, | ||
| whiteSpace: typeInfo.whiteSpace | ||
| }; | ||
@@ -1363,4 +1491,7 @@ if (isArray) { | ||
| resolveAttributes(attrs, props) { | ||
| var _a, _b, _c, _d; | ||
| for (const a of attrs) { | ||
| if (a.ref) { | ||
| const form2 = (_a = a.form) != null ? _a : this.resolveAttributeForm(); | ||
| const defaultOrFixed2 = (_b = a.defaultValue) != null ? _b : a.fixed; | ||
| props.push({ | ||
@@ -1371,5 +1502,8 @@ propertyName: toCamelCase(stripPrefix(a.ref)), | ||
| tsType: "string", | ||
| initializer: a.defaultValue ? `'${escapeString(a.defaultValue)}'` : "''", | ||
| initializer: defaultOrFixed2 ? `'${escapeString2(defaultOrFixed2)}'` : "''", | ||
| required: a.use === "required", | ||
| defaultValue: a.defaultValue | ||
| form: form2, | ||
| namespace: this.resolveNamespaceForForm(form2), | ||
| defaultValue: defaultOrFixed2, | ||
| fixedValue: a.fixed | ||
| }); | ||
@@ -1386,3 +1520,6 @@ continue; | ||
| } | ||
| const initializer = a.defaultValue ? this.buildDefaultInitializer(typeInfo.tsType, a.defaultValue) : typeInfo.initializer; | ||
| const defaultOrFixed = (_c = a.defaultValue) != null ? _c : a.fixed; | ||
| const initializer = defaultOrFixed ? this.buildDefaultInitializer(typeInfo.tsType, defaultOrFixed) : typeInfo.initializer; | ||
| const form = (_d = a.form) != null ? _d : this.resolveAttributeForm(); | ||
| const enumValues = typeInfo.enumValues ? [...typeInfo.enumValues] : a.fixed ? [a.fixed] : void 0; | ||
| props.push({ | ||
@@ -1395,8 +1532,19 @@ propertyName: toCamelCase(a.name), | ||
| required: a.use === "required", | ||
| form: a.form, | ||
| defaultValue: a.defaultValue, | ||
| enumValues: typeInfo.enumValues, | ||
| form, | ||
| namespace: this.resolveNamespaceForForm(form), | ||
| defaultValue: defaultOrFixed, | ||
| fixedValue: a.fixed, | ||
| enumValues, | ||
| pattern: typeInfo.pattern, | ||
| enumTypeName: typeInfo.enumTypeName, | ||
| dataType: typeInfo.dataType | ||
| dataType: typeInfo.dataType, | ||
| minLength: typeInfo.minLength, | ||
| maxLength: typeInfo.maxLength, | ||
| minInclusive: typeInfo.minInclusive, | ||
| maxInclusive: typeInfo.maxInclusive, | ||
| minExclusive: typeInfo.minExclusive, | ||
| maxExclusive: typeInfo.maxExclusive, | ||
| totalDigits: typeInfo.totalDigits, | ||
| fractionDigits: typeInfo.fractionDigits, | ||
| whiteSpace: typeInfo.whiteSpace | ||
| }); | ||
@@ -1440,2 +1588,11 @@ } | ||
| } | ||
| result.minLength = st.restriction.minLength; | ||
| result.maxLength = st.restriction.maxLength; | ||
| result.minInclusive = st.restriction.minInclusive; | ||
| result.maxInclusive = st.restriction.maxInclusive; | ||
| result.minExclusive = st.restriction.minExclusive; | ||
| result.maxExclusive = st.restriction.maxExclusive; | ||
| result.totalDigits = st.restriction.totalDigits; | ||
| result.fractionDigits = st.restriction.fractionDigits; | ||
| result.whiteSpace = st.restriction.whiteSpace; | ||
| return result; | ||
@@ -1490,2 +1647,15 @@ } | ||
| } | ||
| resolveAttributeForm() { | ||
| return this.schema.attributeFormDefault; | ||
| } | ||
| resolveNamespaceForForm(form) { | ||
| if (form !== "qualified" || !this.schema.targetNamespace) { | ||
| return void 0; | ||
| } | ||
| const prefix = this.findPrefixForUri(this.schema.targetNamespace); | ||
| return { | ||
| uri: this.schema.targetNamespace, | ||
| prefix: prefix != null ? prefix : void 0 | ||
| }; | ||
| } | ||
| findPrefixForUri(uri) { | ||
@@ -1500,3 +1670,3 @@ for (const [prefix, nsUri] of this.schema.namespaces) { | ||
| if (tsType === "boolean") return defaultValue === "true" ? "true" : "false"; | ||
| return `'${escapeString(defaultValue)}'`; | ||
| return `'${escapeString2(defaultValue)}'`; | ||
| } | ||
@@ -1509,9 +1679,93 @@ }; | ||
| function toPascalCase(name) { | ||
| return name.replace(/[^a-zA-Z0-9]+(.)/g, (_, c) => c.toUpperCase()).replace(/^[a-z]/, (c) => c.toUpperCase()); | ||
| const converted = name.replace(/[^a-zA-Z0-9]+(.)/g, (_, c) => c.toUpperCase()).replace(/^[a-z]/, (c) => c.toUpperCase()); | ||
| return sanitizeIdentifier(converted, true); | ||
| } | ||
| function toCamelCase(name) { | ||
| const pascal = toPascalCase(name); | ||
| return pascal.charAt(0).toLowerCase() + pascal.slice(1); | ||
| return sanitizeIdentifier(pascal.charAt(0).toLowerCase() + pascal.slice(1), false); | ||
| } | ||
| function escapeString(value) { | ||
| function sanitizeIdentifier(value, pascal) { | ||
| const normalized = value.replace(/[^a-zA-Z0-9_$]/g, ""); | ||
| const nonEmpty = normalized.length > 0 ? normalized : pascal ? "GeneratedType" : "generatedField"; | ||
| const withLeading = /^[A-Za-z_$]/.test(nonEmpty) ? nonEmpty : `_${nonEmpty}`; | ||
| if (RESERVED_TS_IDENTIFIERS.has(withLeading)) { | ||
| return `${withLeading}_`; | ||
| } | ||
| return withLeading; | ||
| } | ||
| var RESERVED_TS_IDENTIFIERS = /* @__PURE__ */ new Set([ | ||
| "abstract", | ||
| "any", | ||
| "as", | ||
| "asserts", | ||
| "async", | ||
| "await", | ||
| "boolean", | ||
| "break", | ||
| "case", | ||
| "catch", | ||
| "class", | ||
| "const", | ||
| "continue", | ||
| "debugger", | ||
| "declare", | ||
| "default", | ||
| "delete", | ||
| "do", | ||
| "else", | ||
| "enum", | ||
| "export", | ||
| "extends", | ||
| "false", | ||
| "finally", | ||
| "for", | ||
| "from", | ||
| "function", | ||
| "get", | ||
| "if", | ||
| "implements", | ||
| "import", | ||
| "in", | ||
| "infer", | ||
| "instanceof", | ||
| "interface", | ||
| "is", | ||
| "keyof", | ||
| "let", | ||
| "module", | ||
| "namespace", | ||
| "never", | ||
| "new", | ||
| "null", | ||
| "number", | ||
| "object", | ||
| "package", | ||
| "private", | ||
| "protected", | ||
| "public", | ||
| "readonly", | ||
| "require", | ||
| "return", | ||
| "set", | ||
| "static", | ||
| "string", | ||
| "super", | ||
| "switch", | ||
| "symbol", | ||
| "this", | ||
| "throw", | ||
| "true", | ||
| "try", | ||
| "type", | ||
| "typeof", | ||
| "undefined", | ||
| "unique", | ||
| "unknown", | ||
| "var", | ||
| "void", | ||
| "while", | ||
| "with", | ||
| "yield" | ||
| ]); | ||
| function escapeString2(value) { | ||
| return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'"); | ||
@@ -1537,4 +1791,5 @@ } | ||
| validateConfig, | ||
| writeGeneratedFile, | ||
| writeGeneratedFiles | ||
| }); | ||
| //# sourceMappingURL=index.js.map |
+301
-47
| // src/config/config-loader.ts | ||
| import fs from "fs"; | ||
| import path from "path"; | ||
| import { pathToFileURL } from "url"; | ||
| import { createJiti } from "jiti"; | ||
| var CONFIG_NAMES = ["xml-poto-codegen.config.ts", "xml-poto-codegen.config.json"]; | ||
@@ -33,4 +33,4 @@ function validateConfig(config) { | ||
| } | ||
| if (!src.outputDir || typeof src.outputDir !== "string") { | ||
| throw new Error(`sources[${index}].outputDir must be a non-empty string.`); | ||
| if (!src.outputPath || typeof src.outputPath !== "string") { | ||
| throw new Error(`sources[${index}].outputPath must be a non-empty string.`); | ||
| } | ||
@@ -60,3 +60,2 @@ if (!isValidOutputStyle(src.outputStyle)) { | ||
| async function loadConfig(configPath) { | ||
| var _a; | ||
| const resolvedPath = configPath ? path.resolve(configPath) : findConfigFile(process.cwd()); | ||
@@ -75,5 +74,9 @@ if (!resolvedPath) { | ||
| } else if (resolvedPath.endsWith(".ts")) { | ||
| const fileUrl = pathToFileURL(resolvedPath).href; | ||
| const mod = await import(fileUrl); | ||
| raw = (_a = mod.default) != null ? _a : mod; | ||
| const jiti = createJiti(__filename); | ||
| const mod = await jiti.import(resolvedPath, { default: true }); | ||
| if (mod && typeof mod === "object" && "default" in mod) { | ||
| raw = mod.default; | ||
| } else { | ||
| raw = mod; | ||
| } | ||
| } else { | ||
@@ -132,2 +135,5 @@ throw new Error(`Unsupported config file format: ${resolvedPath}`); | ||
| const optionalMark = optional ? "?" : ""; | ||
| if (initializer === void 0) { | ||
| return `${name}${optionalMark}: ${type};`; | ||
| } | ||
| return `${name}${optionalMark}: ${type} = ${initializer};`; | ||
@@ -152,9 +158,16 @@ } | ||
| if (type.isRootElement) { | ||
| const opts = { name: `'${type.xmlName}'` }; | ||
| const opts2 = { name: `'${type.xmlName}'` }; | ||
| if (type.namespace) { | ||
| opts.namespace = buildNamespaceObj(type.namespace); | ||
| opts2.namespace = buildNamespaceObj(type.namespace); | ||
| } | ||
| return buildDecorator("XmlRoot", opts); | ||
| if (type.rootNillable) { | ||
| opts2.isNullable = true; | ||
| } | ||
| return buildDecorator("XmlRoot", opts2); | ||
| } | ||
| return buildDecorator("XmlElement", { name: `'${type.xmlName}'` }); | ||
| const opts = { name: `'${type.xmlName}'` }; | ||
| if (type.namespace) { | ||
| opts.namespace = buildNamespaceObj(type.namespace); | ||
| } | ||
| return buildDecorator("XmlElement", opts); | ||
| } | ||
@@ -196,2 +209,3 @@ function mapPropertyDecorator(prop) { | ||
| imports.add("XmlDynamic"); | ||
| imports.add("DynamicElement"); | ||
| break; | ||
@@ -209,2 +223,3 @@ } | ||
| if (prop.form) opts.form = `'${prop.form}'`; | ||
| if (prop.namespace) opts.namespace = buildNamespaceObj(prop.namespace); | ||
| if (prop.defaultValue !== void 0) opts.defaultValue = formatDefault(prop.tsType, prop.defaultValue); | ||
@@ -221,4 +236,5 @@ if (prop.complexTypeName) opts.type = prop.complexTypeName; | ||
| if (prop.defaultValue !== void 0) opts.defaultValue = formatDefault(prop.tsType, prop.defaultValue); | ||
| if (prop.enumValues && prop.enumValues.length > 0) opts.enumValues = prop.enumValues.map((v) => `'${v}'`); | ||
| if (prop.pattern) opts.pattern = `/${prop.pattern}/`; | ||
| if (prop.enumValues && prop.enumValues.length > 0) | ||
| opts.enumValues = prop.enumValues.map((v) => `'${escapeString(v)}'`); | ||
| if (prop.pattern) opts.pattern = `new RegExp(${JSON.stringify(prop.pattern)})`; | ||
| if (prop.dataType) opts.dataType = `'${prop.dataType}'`; | ||
@@ -241,2 +257,3 @@ if (prop.namespace) opts.namespace = buildNamespaceObj(prop.namespace); | ||
| if (prop.isNullable) opts.isNullable = true; | ||
| if (prop.namespace) opts.namespace = buildNamespaceObj(prop.namespace); | ||
| if (prop.dataType) opts.dataType = `'${prop.dataType}'`; | ||
@@ -247,2 +264,3 @@ return buildDecorator("XmlArray", opts); | ||
| const opts = {}; | ||
| if (prop.required) opts.required = true; | ||
| if (prop.order !== void 0) opts.order = prop.order; | ||
@@ -260,4 +278,7 @@ return buildDecorator("XmlDynamic", opts); | ||
| if (tsType === "boolean") return value === "true" ? "true" : "false"; | ||
| return `'${value}'`; | ||
| return `'${escapeString(value)}'`; | ||
| } | ||
| function escapeString(value) { | ||
| return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'"); | ||
| } | ||
@@ -277,7 +298,8 @@ // src/generator/class-generator.ts | ||
| const files = []; | ||
| const resolvedTypes = this.applyRootElements(schema.types, schema.rootElements); | ||
| for (const enumDef of schema.enums) { | ||
| files.push(this.generateEnumFile(enumDef)); | ||
| } | ||
| for (const type of schema.types) { | ||
| files.push(this.generateClassFile(type, schema.types, schema.enums)); | ||
| for (const type of resolvedTypes) { | ||
| files.push(this.generateClassFile(type, resolvedTypes, schema.enums)); | ||
| } | ||
@@ -340,3 +362,4 @@ if (files.length > 0) { | ||
| const parts = [buildFileHeader(this.xsdPath)]; | ||
| for (const type of schema.types) { | ||
| const resolvedTypes = this.applyRootElements(schema.types, schema.rootElements); | ||
| for (const type of resolvedTypes) { | ||
| for (const imp of collectImports(type)) { | ||
@@ -346,3 +369,3 @@ allImports.add(imp); | ||
| } | ||
| const needsDynamic = schema.types.some((t) => t.properties.some((p) => p.kind === "dynamic")); | ||
| const needsDynamic = resolvedTypes.some((t) => t.properties.some((p) => p.kind === "dynamic")); | ||
| if (needsDynamic) { | ||
@@ -358,3 +381,3 @@ allImports.add("DynamicElement"); | ||
| } | ||
| for (const type of schema.types) { | ||
| for (const type of resolvedTypes) { | ||
| parts.push(this.generateClassSource(type)); | ||
@@ -414,4 +437,6 @@ parts.push(""); | ||
| const decorator = mapPropertyDecorator(prop); | ||
| const isOptional = prop.required !== true; | ||
| const initializer = isOptional ? void 0 : prop.initializer; | ||
| lines.push(` ${decorator}`); | ||
| lines.push(` ${buildProperty(prop.propertyName, prop.tsType, prop.initializer)}`); | ||
| lines.push(` ${buildProperty(prop.propertyName, prop.tsType, initializer, isOptional)}`); | ||
| lines.push(""); | ||
@@ -447,2 +472,32 @@ } | ||
| } | ||
| applyRootElements(types, rootElements) { | ||
| if (rootElements.length === 0) { | ||
| return types; | ||
| } | ||
| const rootMap = /* @__PURE__ */ new Map(); | ||
| for (const root of rootElements) { | ||
| const entries = rootMap.get(root.typeName); | ||
| if (entries) { | ||
| entries.push(root); | ||
| } else { | ||
| rootMap.set(root.typeName, [root]); | ||
| } | ||
| } | ||
| return types.map((type) => { | ||
| if (type.isRootElement) { | ||
| return type; | ||
| } | ||
| const roots = rootMap.get(type.className); | ||
| if (!roots || roots.length === 0) { | ||
| return type; | ||
| } | ||
| const root = roots[0]; | ||
| return { | ||
| ...type, | ||
| isRootElement: true, | ||
| xmlName: root.name, | ||
| rootNillable: root.nillable | ||
| }; | ||
| }); | ||
| } | ||
| }; | ||
@@ -454,3 +509,17 @@ function toEnumKey(value) { | ||
| } | ||
| return key.split("_").filter(Boolean).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(""); | ||
| const hadLeadingUnderscore = key.startsWith("_"); | ||
| let result = key.split("_").filter(Boolean).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(""); | ||
| if (hadLeadingUnderscore && !result.startsWith("_")) { | ||
| result = `_${result}`; | ||
| } | ||
| if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(result)) { | ||
| result = result.replace(/^[^A-Za-z_]+/, ""); | ||
| if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(result)) { | ||
| result = `_${result}`; | ||
| } | ||
| if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(result)) { | ||
| result = "_Value"; | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
@@ -471,2 +540,8 @@ | ||
| } | ||
| function writeGeneratedFile(outputFilePath, file) { | ||
| const parentDir = path2.dirname(outputFilePath); | ||
| fs2.mkdirSync(parentDir, { recursive: true }); | ||
| fs2.writeFileSync(outputFilePath, file.content, "utf-8"); | ||
| return outputFilePath; | ||
| } | ||
@@ -751,3 +826,3 @@ // src/xsd/xsd-parser.ts | ||
| parseSimpleContentRestriction(obj) { | ||
| var _a, _b; | ||
| var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k; | ||
| return { | ||
@@ -760,2 +835,11 @@ base: (_a = attr(obj, "base")) != null ? _a : "", | ||
| pattern: attr((_b = this.getChild(obj, this.xsd("pattern"))) != null ? _b : {}, "value"), | ||
| minLength: numAttr((_c = this.getChild(obj, this.xsd("minLength"))) != null ? _c : {}, "value"), | ||
| maxLength: numAttr((_d = this.getChild(obj, this.xsd("maxLength"))) != null ? _d : {}, "value"), | ||
| minInclusive: numAttr((_e = this.getChild(obj, this.xsd("minInclusive"))) != null ? _e : {}, "value"), | ||
| maxInclusive: numAttr((_f = this.getChild(obj, this.xsd("maxInclusive"))) != null ? _f : {}, "value"), | ||
| minExclusive: numAttr((_g = this.getChild(obj, this.xsd("minExclusive"))) != null ? _g : {}, "value"), | ||
| maxExclusive: numAttr((_h = this.getChild(obj, this.xsd("maxExclusive"))) != null ? _h : {}, "value"), | ||
| totalDigits: numAttr((_i = this.getChild(obj, this.xsd("totalDigits"))) != null ? _i : {}, "value"), | ||
| fractionDigits: numAttr((_j = this.getChild(obj, this.xsd("fractionDigits"))) != null ? _j : {}, "value"), | ||
| whiteSpace: attr((_k = this.getChild(obj, this.xsd("whiteSpace"))) != null ? _k : {}, "value"), | ||
| attributes: this.parseChildren(obj, this.xsd("attribute")).map((a) => this.parseAttribute(a)) | ||
@@ -1044,12 +1128,34 @@ }; | ||
| buildAttributeGroupLookups() { | ||
| const groupDefs = /* @__PURE__ */ new Map(); | ||
| for (const ag of this.schema.attributeGroups) { | ||
| if (ag.name) { | ||
| const attrs = [...ag.attributes]; | ||
| for (const ref of ag.attributeGroupRefs) { | ||
| const refName = stripPrefix(ref.ref); | ||
| const resolved = this.attributeGroupMap.get(refName); | ||
| if (resolved) attrs.push(...resolved); | ||
| groupDefs.set(ag.name, ag); | ||
| } | ||
| } | ||
| const resolving = /* @__PURE__ */ new Set(); | ||
| const resolveGroup = (name) => { | ||
| const cached = this.attributeGroupMap.get(name); | ||
| if (cached) return cached; | ||
| const def = groupDefs.get(name); | ||
| if (!def) { | ||
| return []; | ||
| } | ||
| if (resolving.has(name)) { | ||
| return []; | ||
| } | ||
| resolving.add(name); | ||
| const attrs = [...def.attributes]; | ||
| for (const ref of def.attributeGroupRefs) { | ||
| const refName = stripPrefix(ref.ref); | ||
| const resolvedAttrs = resolveGroup(refName); | ||
| if (resolvedAttrs.length) { | ||
| attrs.push(...resolvedAttrs); | ||
| } | ||
| this.attributeGroupMap.set(ag.name, attrs); | ||
| } | ||
| resolving.delete(name); | ||
| this.attributeGroupMap.set(name, attrs); | ||
| return attrs; | ||
| }; | ||
| for (const name of groupDefs.keys()) { | ||
| resolveGroup(name); | ||
| } | ||
@@ -1094,3 +1200,3 @@ } | ||
| } | ||
| let order = 0; | ||
| let order = 1; | ||
| if (ct.sequence) { | ||
@@ -1147,2 +1253,11 @@ order = this.resolveSequenceProperties(ct.sequence, resolved.properties, order); | ||
| pattern: sc.restriction.pattern, | ||
| minLength: sc.restriction.minLength, | ||
| maxLength: sc.restriction.maxLength, | ||
| minInclusive: sc.restriction.minInclusive, | ||
| maxInclusive: sc.restriction.maxInclusive, | ||
| minExclusive: sc.restriction.minExclusive, | ||
| maxExclusive: sc.restriction.maxExclusive, | ||
| totalDigits: sc.restriction.totalDigits, | ||
| fractionDigits: sc.restriction.fractionDigits, | ||
| whiteSpace: sc.restriction.whiteSpace, | ||
| dataType: baseInfo.dataType | ||
@@ -1156,3 +1271,3 @@ }); | ||
| resolved.baseTypeName = toPascalCase(stripPrefix(cc.extension.base)); | ||
| let order = 0; | ||
| let order = 1; | ||
| if (cc.extension.sequence) { | ||
@@ -1179,3 +1294,3 @@ order = this.resolveSequenceProperties(cc.extension.sequence, resolved.properties, order); | ||
| if (cc.restriction.sequence) { | ||
| this.resolveSequenceProperties(cc.restriction.sequence, resolved.properties, 0); | ||
| this.resolveSequenceProperties(cc.restriction.sequence, resolved.properties, 1); | ||
| } | ||
@@ -1208,3 +1323,3 @@ this.resolveAttributes(cc.restriction.attributes, resolved.properties); | ||
| }); | ||
| if (any.minOccurs !== void 0 && any.minOccurs > 0) { | ||
| if (any.minOccurs === void 0 || any.minOccurs > 0) { | ||
| props[props.length - 1].required = true; | ||
@@ -1251,5 +1366,6 @@ } | ||
| resolveElementProperty(el, order) { | ||
| var _a; | ||
| var _a, _b; | ||
| const isArray = el.maxOccurs === "unbounded" || typeof el.maxOccurs === "number" && el.maxOccurs > 1; | ||
| const isRequired = el.minOccurs === void 0 || el.minOccurs > 0; | ||
| const form = (_a = el.form) != null ? _a : this.resolveElementForm(); | ||
| const name = el.ref ? stripPrefix(el.ref) : el.name; | ||
@@ -1292,4 +1408,6 @@ if (this.substitutionMap.has(name)) { | ||
| isNullable: el.nillable, | ||
| form: (_a = el.form) != null ? _a : this.resolveElementForm(), | ||
| defaultValue: el.defaultValue, | ||
| form, | ||
| namespace: this.resolveNamespaceForForm(form), | ||
| defaultValue: (_b = el.defaultValue) != null ? _b : el.fixed, | ||
| fixedValue: el.fixed, | ||
| complexTypeName: typeInfo.complexTypeName, | ||
@@ -1299,3 +1417,12 @@ enumValues: typeInfo.enumValues, | ||
| enumTypeName: typeInfo.enumTypeName, | ||
| dataType: typeInfo.dataType | ||
| dataType: typeInfo.dataType, | ||
| minLength: typeInfo.minLength, | ||
| maxLength: typeInfo.maxLength, | ||
| minInclusive: typeInfo.minInclusive, | ||
| maxInclusive: typeInfo.maxInclusive, | ||
| minExclusive: typeInfo.minExclusive, | ||
| maxExclusive: typeInfo.maxExclusive, | ||
| totalDigits: typeInfo.totalDigits, | ||
| fractionDigits: typeInfo.fractionDigits, | ||
| whiteSpace: typeInfo.whiteSpace | ||
| }; | ||
@@ -1309,4 +1436,7 @@ if (isArray) { | ||
| resolveAttributes(attrs, props) { | ||
| var _a, _b, _c, _d; | ||
| for (const a of attrs) { | ||
| if (a.ref) { | ||
| const form2 = (_a = a.form) != null ? _a : this.resolveAttributeForm(); | ||
| const defaultOrFixed2 = (_b = a.defaultValue) != null ? _b : a.fixed; | ||
| props.push({ | ||
@@ -1317,5 +1447,8 @@ propertyName: toCamelCase(stripPrefix(a.ref)), | ||
| tsType: "string", | ||
| initializer: a.defaultValue ? `'${escapeString(a.defaultValue)}'` : "''", | ||
| initializer: defaultOrFixed2 ? `'${escapeString2(defaultOrFixed2)}'` : "''", | ||
| required: a.use === "required", | ||
| defaultValue: a.defaultValue | ||
| form: form2, | ||
| namespace: this.resolveNamespaceForForm(form2), | ||
| defaultValue: defaultOrFixed2, | ||
| fixedValue: a.fixed | ||
| }); | ||
@@ -1332,3 +1465,6 @@ continue; | ||
| } | ||
| const initializer = a.defaultValue ? this.buildDefaultInitializer(typeInfo.tsType, a.defaultValue) : typeInfo.initializer; | ||
| const defaultOrFixed = (_c = a.defaultValue) != null ? _c : a.fixed; | ||
| const initializer = defaultOrFixed ? this.buildDefaultInitializer(typeInfo.tsType, defaultOrFixed) : typeInfo.initializer; | ||
| const form = (_d = a.form) != null ? _d : this.resolveAttributeForm(); | ||
| const enumValues = typeInfo.enumValues ? [...typeInfo.enumValues] : a.fixed ? [a.fixed] : void 0; | ||
| props.push({ | ||
@@ -1341,8 +1477,19 @@ propertyName: toCamelCase(a.name), | ||
| required: a.use === "required", | ||
| form: a.form, | ||
| defaultValue: a.defaultValue, | ||
| enumValues: typeInfo.enumValues, | ||
| form, | ||
| namespace: this.resolveNamespaceForForm(form), | ||
| defaultValue: defaultOrFixed, | ||
| fixedValue: a.fixed, | ||
| enumValues, | ||
| pattern: typeInfo.pattern, | ||
| enumTypeName: typeInfo.enumTypeName, | ||
| dataType: typeInfo.dataType | ||
| dataType: typeInfo.dataType, | ||
| minLength: typeInfo.minLength, | ||
| maxLength: typeInfo.maxLength, | ||
| minInclusive: typeInfo.minInclusive, | ||
| maxInclusive: typeInfo.maxInclusive, | ||
| minExclusive: typeInfo.minExclusive, | ||
| maxExclusive: typeInfo.maxExclusive, | ||
| totalDigits: typeInfo.totalDigits, | ||
| fractionDigits: typeInfo.fractionDigits, | ||
| whiteSpace: typeInfo.whiteSpace | ||
| }); | ||
@@ -1386,2 +1533,11 @@ } | ||
| } | ||
| result.minLength = st.restriction.minLength; | ||
| result.maxLength = st.restriction.maxLength; | ||
| result.minInclusive = st.restriction.minInclusive; | ||
| result.maxInclusive = st.restriction.maxInclusive; | ||
| result.minExclusive = st.restriction.minExclusive; | ||
| result.maxExclusive = st.restriction.maxExclusive; | ||
| result.totalDigits = st.restriction.totalDigits; | ||
| result.fractionDigits = st.restriction.fractionDigits; | ||
| result.whiteSpace = st.restriction.whiteSpace; | ||
| return result; | ||
@@ -1436,2 +1592,15 @@ } | ||
| } | ||
| resolveAttributeForm() { | ||
| return this.schema.attributeFormDefault; | ||
| } | ||
| resolveNamespaceForForm(form) { | ||
| if (form !== "qualified" || !this.schema.targetNamespace) { | ||
| return void 0; | ||
| } | ||
| const prefix = this.findPrefixForUri(this.schema.targetNamespace); | ||
| return { | ||
| uri: this.schema.targetNamespace, | ||
| prefix: prefix != null ? prefix : void 0 | ||
| }; | ||
| } | ||
| findPrefixForUri(uri) { | ||
@@ -1446,3 +1615,3 @@ for (const [prefix, nsUri] of this.schema.namespaces) { | ||
| if (tsType === "boolean") return defaultValue === "true" ? "true" : "false"; | ||
| return `'${escapeString(defaultValue)}'`; | ||
| return `'${escapeString2(defaultValue)}'`; | ||
| } | ||
@@ -1455,9 +1624,93 @@ }; | ||
| function toPascalCase(name) { | ||
| return name.replace(/[^a-zA-Z0-9]+(.)/g, (_, c) => c.toUpperCase()).replace(/^[a-z]/, (c) => c.toUpperCase()); | ||
| const converted = name.replace(/[^a-zA-Z0-9]+(.)/g, (_, c) => c.toUpperCase()).replace(/^[a-z]/, (c) => c.toUpperCase()); | ||
| return sanitizeIdentifier(converted, true); | ||
| } | ||
| function toCamelCase(name) { | ||
| const pascal = toPascalCase(name); | ||
| return pascal.charAt(0).toLowerCase() + pascal.slice(1); | ||
| return sanitizeIdentifier(pascal.charAt(0).toLowerCase() + pascal.slice(1), false); | ||
| } | ||
| function escapeString(value) { | ||
| function sanitizeIdentifier(value, pascal) { | ||
| const normalized = value.replace(/[^a-zA-Z0-9_$]/g, ""); | ||
| const nonEmpty = normalized.length > 0 ? normalized : pascal ? "GeneratedType" : "generatedField"; | ||
| const withLeading = /^[A-Za-z_$]/.test(nonEmpty) ? nonEmpty : `_${nonEmpty}`; | ||
| if (RESERVED_TS_IDENTIFIERS.has(withLeading)) { | ||
| return `${withLeading}_`; | ||
| } | ||
| return withLeading; | ||
| } | ||
| var RESERVED_TS_IDENTIFIERS = /* @__PURE__ */ new Set([ | ||
| "abstract", | ||
| "any", | ||
| "as", | ||
| "asserts", | ||
| "async", | ||
| "await", | ||
| "boolean", | ||
| "break", | ||
| "case", | ||
| "catch", | ||
| "class", | ||
| "const", | ||
| "continue", | ||
| "debugger", | ||
| "declare", | ||
| "default", | ||
| "delete", | ||
| "do", | ||
| "else", | ||
| "enum", | ||
| "export", | ||
| "extends", | ||
| "false", | ||
| "finally", | ||
| "for", | ||
| "from", | ||
| "function", | ||
| "get", | ||
| "if", | ||
| "implements", | ||
| "import", | ||
| "in", | ||
| "infer", | ||
| "instanceof", | ||
| "interface", | ||
| "is", | ||
| "keyof", | ||
| "let", | ||
| "module", | ||
| "namespace", | ||
| "never", | ||
| "new", | ||
| "null", | ||
| "number", | ||
| "object", | ||
| "package", | ||
| "private", | ||
| "protected", | ||
| "public", | ||
| "readonly", | ||
| "require", | ||
| "return", | ||
| "set", | ||
| "static", | ||
| "string", | ||
| "super", | ||
| "switch", | ||
| "symbol", | ||
| "this", | ||
| "throw", | ||
| "true", | ||
| "try", | ||
| "type", | ||
| "typeof", | ||
| "undefined", | ||
| "unique", | ||
| "unknown", | ||
| "var", | ||
| "void", | ||
| "while", | ||
| "with", | ||
| "yield" | ||
| ]); | ||
| function escapeString2(value) { | ||
| return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'"); | ||
@@ -1482,4 +1735,5 @@ } | ||
| validateConfig, | ||
| writeGeneratedFile, | ||
| writeGeneratedFiles | ||
| }; | ||
| //# sourceMappingURL=index.mjs.map |
+2
-2
| { | ||
| "name": "@cerios/xml-poto-codegen", | ||
| "version": "0.1.0", | ||
| "version": "0.1.1", | ||
| "description": "Generate TypeScript classes with xml-poto decorators from XSD schemas. CLI tool with config-based multi-XSD support.", | ||
@@ -27,3 +27,3 @@ "keywords": [ | ||
| "bin": { | ||
| "xml-poto-codegen": "./dist/cli.js" | ||
| "xml-poto-codegen": "dist/cli.js" | ||
| }, | ||
@@ -30,0 +30,0 @@ "files": [ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
875970
18.5%8188
21.86%17
13.33%